piotr | 437f546 | 2014-02-04 17:57:25 +0100 | [diff] [blame] | 1 | # 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 | |
| 20 | if(DEFINED __INCLUDED_GR_SWIG_CMAKE) |
| 21 | return() |
| 22 | endif() |
| 23 | set(__INCLUDED_GR_SWIG_CMAKE TRUE) |
| 24 | |
| 25 | include(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 | ######################################################################## |
| 35 | function(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) |
| 90 | endfunction(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 | ######################################################################## |
| 105 | macro(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 | |
| 161 | endmacro(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 | ######################################################################## |
| 171 | macro(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 | |
| 195 | endmacro(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 | ######################################################################## |
| 203 | file(WRITE ${CMAKE_BINARY_DIR}/get_swig_deps.py " |
| 204 | |
| 205 | import os, sys, re |
| 206 | |
| 207 | include_matcher = re.compile('[#|%]include\\s*[<|\"](.*)[>|\"]') |
| 208 | include_dirs = sys.argv[2].split(';') |
| 209 | |
| 210 | def get_swig_incs(file_path): |
| 211 | file_contents = open(file_path, 'r').read() |
| 212 | return include_matcher.findall(file_contents, re.MULTILINE) |
| 213 | |
| 214 | def 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 | |
| 224 | if __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 | ") |