blob: 569667b0e9549fbd254a0e70c740b1a9f0faade2 [file] [log] [blame]
piotr437f5462014-02-04 17:57:25 +01001# Copyright 2010-2011 Free Software Foundation, Inc.
2#
3# This file is part of GNU Radio
4#
5# GNU Radio is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3, or (at your option)
8# any later version.
9#
10# GNU Radio is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with GNU Radio; see the file COPYING. If not, write to
17# the Free Software Foundation, Inc., 51 Franklin Street,
18# Boston, MA 02110-1301, USA.
19
20if(DEFINED __INCLUDED_GR_SWIG_CMAKE)
21 return()
22endif()
23set(__INCLUDED_GR_SWIG_CMAKE TRUE)
24
25include(GrPython)
26
27########################################################################
28# Builds a swig documentation file to be generated into python docstrings
29# Usage: GR_SWIG_MAKE_DOCS(output_file input_path input_path....)
30#
31# Set the following variable to specify extra dependent targets:
32# - GR_SWIG_DOCS_SOURCE_DEPS
33# - GR_SWIG_DOCS_TARGET_DEPS
34########################################################################
35function(GR_SWIG_MAKE_DOCS output_file)
36 find_package(Doxygen)
37 if(DOXYGEN_FOUND)
38
39 #setup the input files variable list, quote formated
40 set(input_files)
41 unset(INPUT_PATHS)
42 foreach(input_path ${ARGN})
43 if (IS_DIRECTORY ${input_path}) #when input path is a directory
44 file(GLOB input_path_h_files ${input_path}/*.h)
45 else() #otherwise its just a file, no glob
46 set(input_path_h_files ${input_path})
47 endif()
48 list(APPEND input_files ${input_path_h_files})
49 set(INPUT_PATHS "${INPUT_PATHS} \"${input_path}\"")
50 endforeach(input_path)
51
52 #determine the output directory
53 get_filename_component(name ${output_file} NAME_WE)
54 get_filename_component(OUTPUT_DIRECTORY ${output_file} PATH)
55 set(OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY}/${name}_swig_docs)
56 make_directory(${OUTPUT_DIRECTORY})
57
58 #generate the Doxyfile used by doxygen
59 configure_file(
60 ${CMAKE_SOURCE_DIR}/docs/doxygen/Doxyfile.swig_doc.in
61 ${OUTPUT_DIRECTORY}/Doxyfile
62 @ONLY)
63
64 #Create a dummy custom command that depends on other targets
65 include(GrMiscUtils)
66 GR_GEN_TARGET_DEPS(_${name}_tag tag_deps ${GR_SWIG_DOCS_TARGET_DEPS})
67
68 #call doxygen on the Doxyfile + input headers
69 add_custom_command(
70 OUTPUT ${OUTPUT_DIRECTORY}/xml/index.xml
71 DEPENDS ${input_files} ${GR_SWIG_DOCS_SOURCE_DEPS} ${tag_deps}
72 COMMAND ${DOXYGEN_EXECUTABLE} ${OUTPUT_DIRECTORY}/Doxyfile
73 COMMENT "Generating doxygen xml for ${name} docs"
74 )
75
76 #call the swig_doc script on the xml files
77 add_custom_command(
78 OUTPUT ${output_file}
79 DEPENDS ${input_files} ${OUTPUT_DIRECTORY}/xml/index.xml
80 COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
81 ${CMAKE_SOURCE_DIR}/docs/doxygen/swig_doc.py
82 ${OUTPUT_DIRECTORY}/xml
83 ${output_file}
84 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/doxygen
85 )
86
87 else(DOXYGEN_FOUND)
88 file(WRITE ${output_file} "\n") #no doxygen -> empty file
89 endif(DOXYGEN_FOUND)
90endfunction(GR_SWIG_MAKE_DOCS)
91
92########################################################################
93# Build a swig target for the common gnuradio use case. Usage:
94# GR_SWIG_MAKE(target ifile ifile ifile...)
95#
96# Set the following variables before calling:
97# - GR_SWIG_FLAGS
98# - GR_SWIG_INCLUDE_DIRS
99# - GR_SWIG_LIBRARIES
100# - GR_SWIG_SOURCE_DEPS
101# - GR_SWIG_TARGET_DEPS
102# - GR_SWIG_DOC_FILE
103# - GR_SWIG_DOC_DIRS
104########################################################################
105macro(GR_SWIG_MAKE name)
106 set(ifiles ${ARGN})
107
108 #do swig doc generation if specified
109 if (GR_SWIG_DOC_FILE)
110 set(GR_SWIG_DOCS_SOURCE_DEPS ${GR_SWIG_SOURCE_DEPS})
111 set(GR_SWIG_DOCS_TAREGT_DEPS ${GR_SWIG_TARGET_DEPS})
112 GR_SWIG_MAKE_DOCS(${GR_SWIG_DOC_FILE} ${GR_SWIG_DOC_DIRS})
113 list(APPEND GR_SWIG_SOURCE_DEPS ${GR_SWIG_DOC_FILE})
114 endif()
115
116 #append additional include directories
117 find_package(PythonLibs 2)
118 list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_PATH}) #deprecated name (now dirs)
119 list(APPEND GR_SWIG_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS})
120 list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
121 list(APPEND GR_SWIG_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR})
122
123 #determine include dependencies for swig file
124 execute_process(
125 COMMAND ${PYTHON_EXECUTABLE}
126 ${CMAKE_BINARY_DIR}/get_swig_deps.py
127 "${ifiles}" "${GR_SWIG_INCLUDE_DIRS}"
128 OUTPUT_STRIP_TRAILING_WHITESPACE
129 OUTPUT_VARIABLE SWIG_MODULE_${name}_EXTRA_DEPS
130 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
131 )
132
133 #Create a dummy custom command that depends on other targets
134 include(GrMiscUtils)
135 GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
136 set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
137 add_custom_command(
138 OUTPUT ${tag_file}
139 DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
140 COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
141 )
142
143 #append the specified include directories
144 include_directories(${GR_SWIG_INCLUDE_DIRS})
145 list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
146
147 #setup the swig flags with flags and include directories
148 set(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
149 foreach(dir ${GR_SWIG_INCLUDE_DIRS})
150 list(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
151 endforeach(dir)
152
153 #set the C++ property on the swig .i file so it builds
154 set_source_files_properties(${ifiles} PROPERTIES CPLUSPLUS ON)
155
156 #setup the actual swig library target to be built
157 include(UseSWIG)
158 SWIG_ADD_MODULE(${name} python ${ifiles})
159 SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
160
161endmacro(GR_SWIG_MAKE)
162
163########################################################################
164# Install swig targets generated by GR_SWIG_MAKE. Usage:
165# GR_SWIG_INSTALL(
166# TARGETS target target target...
167# [DESTINATION destination]
168# [COMPONENT component]
169# )
170########################################################################
171macro(GR_SWIG_INSTALL)
172
173 include(CMakeParseArgumentsCopy)
174 CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
175
176 foreach(name ${GR_SWIG_INSTALL_TARGETS})
177 install(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
178 DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
179 COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
180 )
181
182 include(GrPython)
183 GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
184 DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
185 COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
186 )
187
188 GR_LIBTOOL(
189 TARGET ${SWIG_MODULE_${name}_REAL_NAME}
190 DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
191 )
192
193 endforeach(name)
194
195endmacro(GR_SWIG_INSTALL)
196
197########################################################################
198# Generate a python file that can determine swig dependencies.
199# Used by the make macro above to determine extra dependencies.
200# When you build C++, CMake figures out the header dependencies.
201# This code essentially performs that logic for swig includes.
202########################################################################
203file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py "
204
205import os, sys, re
206
207include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]')
208include_dirs = sys.argv[2].split(';')
209
210def get_swig_incs(file_path):
211 file_contents = open(file_path, 'r').read()
212 return include_matcher.findall(file_contents, re.MULTILINE)
213
214def get_swig_deps(file_path, level):
215 deps = [file_path]
216 if level == 0: return deps
217 for inc_file in get_swig_incs(file_path):
218 for inc_dir in include_dirs:
219 inc_path = os.path.join(inc_dir, inc_file)
220 if not os.path.exists(inc_path): continue
221 deps.extend(get_swig_deps(inc_path, level-1))
222 return deps
223
224if __name__ == '__main__':
225 ifiles = sys.argv[1].split(';')
226 deps = sum([get_swig_deps(ifile, 3) for ifile in ifiles], [])
227 #sys.stderr.write(';'.join(set(deps)) + '\\n\\n')
228 print(';'.join(set(deps)))
229")