From 81dbc190bebe6f623aa5603394dcc691110f55fb Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Sat, 5 Nov 2011 13:54:35 -0700
Subject: cmake: tweaks to swig gen and updated howto modules

---
 .../cmake/Modules/GrMiscUtils.cmake                | 204 +++++++++++++++++++++
 .../cmake/Modules/GrPython.cmake                   |  90 +++++++--
 .../cmake/Modules/GrSwig.cmake                     |  21 ++-
 3 files changed, 291 insertions(+), 24 deletions(-)
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/GrMiscUtils.cmake

(limited to 'gr-howto-write-a-block-cmake/cmake/Modules')

diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrMiscUtils.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrMiscUtils.cmake
new file mode 100644
index 0000000000..540b97b93b
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrMiscUtils.cmake
@@ -0,0 +1,204 @@
+# Copyright 2010-2011 Free Software Foundation, Inc.
+# 
+# This file is part of GNU Radio
+# 
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+if(DEFINED __INCLUDED_GR_MISC_UTILS_CMAKE)
+    return()
+endif()
+set(__INCLUDED_GR_MISC_UTILS_CMAKE TRUE)
+
+########################################################################
+# Set global variable macro.
+# Used for subdirectories to export settings.
+# Example: include and library paths.
+########################################################################
+function(GR_SET_GLOBAL var)
+    set(${var} ${ARGN} CACHE INTERNAL "" FORCE)
+endfunction(GR_SET_GLOBAL)
+
+########################################################################
+# Set the pre-processor definition if the condition is true.
+#  - def the pre-processor definition to set and condition name
+########################################################################
+function(GR_ADD_COND_DEF def)
+    if(${def})
+        add_definitions(-D${def})
+    endif(${def})
+endfunction(GR_ADD_COND_DEF)
+
+########################################################################
+# Check for a header and conditionally set a compile define.
+#  - hdr the relative path to the header file
+#  - def the pre-processor definition to set
+########################################################################
+function(GR_CHECK_HDR_N_DEF hdr def)
+    include(CheckIncludeFileCXX)
+    CHECK_INCLUDE_FILE_CXX(${hdr} ${def})
+    GR_ADD_COND_DEF(${def})
+endfunction(GR_CHECK_HDR_N_DEF)
+
+########################################################################
+# Include subdirectory macro.
+# Sets the CMake directory variables,
+# includes the subdirectory CMakeLists.txt,
+# resets the CMake directory variables.
+#
+# This macro includes subdirectories rather than adding them
+# so that the subdirectory can affect variables in the level above.
+# This provides a work-around for the lack of convenience libraries.
+# This way a subdirectory can append to the list of library sources.
+########################################################################
+macro(GR_INCLUDE_SUBDIRECTORY subdir)
+    #insert the current directories on the front of the list
+    list(INSERT _cmake_source_dirs 0 ${CMAKE_CURRENT_SOURCE_DIR})
+    list(INSERT _cmake_binary_dirs 0 ${CMAKE_CURRENT_BINARY_DIR})
+
+    #set the current directories to the names of the subdirs
+    set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${subdir})
+    set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${subdir})
+
+    #include the subdirectory CMakeLists to run it
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+    include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
+
+    #reset the value of the current directories
+    list(GET _cmake_source_dirs 0 CMAKE_CURRENT_SOURCE_DIR)
+    list(GET _cmake_binary_dirs 0 CMAKE_CURRENT_BINARY_DIR)
+
+    #pop the subdir names of the front of the list
+    list(REMOVE_AT _cmake_source_dirs 0)
+    list(REMOVE_AT _cmake_binary_dirs 0)
+endmacro(GR_INCLUDE_SUBDIRECTORY)
+
+########################################################################
+# Check if a compiler flag works and conditionally set a compile define.
+#  - flag the compiler flag to check for
+#  - have the variable to set with result
+########################################################################
+macro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
+    include(CheckCXXCompilerFlag)
+    CHECK_CXX_COMPILER_FLAG(${flag} ${have})
+    if(${have})
+        add_definitions(${flag})
+    endif(${have})
+endmacro(GR_ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
+
+########################################################################
+# Generates the .la libtool file
+# This appears to generate libtool files that cannot be used by auto*.
+# Usage GR_LIBTOOL(TARGET [target] DESTINATION [dest])
+# Notice: there is not COMPONENT option, these will not get distributed.
+########################################################################
+function(GR_LIBTOOL)
+    if(NOT DEFINED GENERATE_LIBTOOL)
+        set(GENERATE_LIBTOOL OFF) #disabled by default
+    endif()
+
+    if(GENERATE_LIBTOOL)
+        include(CMakeParseArgumentsCopy)
+        CMAKE_PARSE_ARGUMENTS(GR_LIBTOOL "" "TARGET;DESTINATION" "" ${ARGN})
+
+        find_program(LIBTOOL libtool)
+        if(LIBTOOL)
+            include(CMakeMacroLibtoolFile)
+            CREATE_LIBTOOL_FILE(${GR_LIBTOOL_TARGET} /${GR_LIBTOOL_DESTINATION})
+        endif(LIBTOOL)
+    endif(GENERATE_LIBTOOL)
+
+endfunction(GR_LIBTOOL)
+
+########################################################################
+# Do standard things to the library target
+# - set target properties
+# - make install rules
+# Also handle gnuradio custom naming conventions w/ extras mode.
+########################################################################
+function(GR_LIBRARY_FOO target)
+    #parse the arguments for component names
+    include(CMakeParseArgumentsCopy)
+    CMAKE_PARSE_ARGUMENTS(GR_LIBRARY "" "RUNTIME_COMPONENT;DEVEL_COMPONENT" "" ${ARGN})
+
+    #set additional target properties
+    set_target_properties(${target} PROPERTIES SOVERSION ${LIBVER})
+
+    #install the generated files like so...
+    install(TARGETS ${target}
+        LIBRARY DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .so/.dylib file
+        ARCHIVE DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_DEVEL_COMPONENT}   # .lib file
+        RUNTIME DESTINATION ${GR_RUNTIME_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT} # .dll file
+    )
+
+    #extras mode enabled automatically on linux
+    if(NOT DEFINED LIBRARY_EXTRAS)
+        set(LIBRARY_EXTRAS ${LINUX})
+    endif()
+
+    #special extras mode to enable alternative naming conventions
+    if(LIBRARY_EXTRAS)
+
+        #create .la file before changing props
+        GR_LIBTOOL(TARGET ${target} DESTINATION ${GR_LIBRARY_DIR})
+
+        #give the library a special name with ultra-zero soversion
+        set_target_properties(${target} PROPERTIES LIBRARY_OUTPUT_NAME ${target}-${LIBVER} SOVERSION "0.0.0")
+        set(target_name lib${target}-${LIBVER}.so.0.0.0)
+
+        #custom command to generate symlinks
+        add_custom_command(
+            TARGET ${target}
+            POST_BUILD
+            COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
+            COMMAND ${CMAKE_COMMAND} -E create_symlink ${target_name} ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
+        )
+
+        #and install the extra symlinks
+        install(
+            FILES
+            ${CMAKE_CURRENT_BINARY_DIR}/lib${target}.so
+            ${CMAKE_CURRENT_BINARY_DIR}/lib${target}-${LIBVER}.so.0
+            DESTINATION ${GR_LIBRARY_DIR} COMPONENT ${GR_LIBRARY_RUNTIME_COMPONENT}
+        )
+
+    endif(LIBRARY_EXTRAS)
+endfunction(GR_LIBRARY_FOO)
+
+########################################################################
+# Create a dummy custom command that depends on other targets.
+# Usage:
+#   GR_GEN_TARGET_DEPS(unique_name target_deps <target1> <target2> ...)
+#   ADD_CUSTOM_COMMAND(<the usual args> ${target_deps})
+#
+# Custom command cant depend on targets, but can depend on executables,
+# and executables can depend on targets. So this is the process:
+########################################################################
+function(GR_GEN_TARGET_DEPS name var)
+    file(
+        WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
+        "int main(void){return 0;}\n"
+    )
+    execute_process(
+        COMMAND ${CMAKE_COMMAND} -E copy_if_different
+        ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp.in
+        ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp
+    )
+    add_executable(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}.cpp)
+    if(ARGN)
+        add_dependencies(${name} ${ARGN})
+    endif(ARGN)
+    set(${var} "DEPENDS;${name};COMMAND;${name}" PARENT_SCOPE)
+endfunction(GR_GEN_TARGET_DEPS)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
index da0590d42f..efdddf371f 100644
--- a/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
@@ -1,17 +1,17 @@
 # Copyright 2010-2011 Free Software Foundation, Inc.
-# 
+#
 # This file is part of GNU Radio
-# 
+#
 # GNU Radio is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3, or (at your option)
 # any later version.
-# 
+#
 # GNU Radio is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with GNU Radio; see the file COPYING.  If not, write to
 # the Free Software Foundation, Inc., 51 Franklin Street,
@@ -51,6 +51,18 @@ endif(PYTHON_EXECUTABLE)
 #make the path to the executable appear in the cmake gui
 set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
 
+#make sure we can use -B with python (introduced in 2.6)
+if(PYTHON_EXECUTABLE)
+    execute_process(
+        COMMAND ${PYTHON_EXECUTABLE} -B -c ""
+        OUTPUT_QUIET ERROR_QUIET
+        RESULT_VARIABLE PYTHON_HAS_DASH_B_RESULT
+    )
+    if(PYTHON_HAS_DASH_B_RESULT EQUAL 0)
+        set(PYTHON_DASH_B "-B")
+    endif()
+endif(PYTHON_EXECUTABLE)
+
 ########################################################################
 # Check for the existence of a python module:
 # - desc a string description of the check
@@ -115,28 +127,55 @@ function(GR_PYTHON_INSTALL)
     ####################################################################
         install(${ARGN}) #installs regular python files
 
+        #create a list of all generated files
+        unset(pysrcfiles)
+        unset(pycfiles)
+        unset(pyofiles)
         foreach(pyfile ${GR_PYTHON_INSTALL_FILES})
-            get_filename_component(pyfile_name ${pyfile} NAME)
             get_filename_component(pyfile ${pyfile} ABSOLUTE)
-            string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pycfile "${pyfile}c")
-            list(APPEND python_install_gen_targets ${pycfile})
+            list(APPEND pysrcfiles ${pyfile})
+
+            #determine if this file is in the source or binary directory
+            file(RELATIVE_PATH source_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${pyfile})
+            string(LENGTH "${source_rel_path}" source_rel_path_len)
+            file(RELATIVE_PATH binary_rel_path ${CMAKE_CURRENT_BINARY_DIR} ${pyfile})
+            string(LENGTH "${binary_rel_path}" binary_rel_path_len)
+
+            #and set the generated path appropriately
+            if(${source_rel_path_len} GREATER ${binary_rel_path_len})
+                set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${binary_rel_path})
+            else()
+                set(pygenfile ${CMAKE_CURRENT_BINARY_DIR}/${source_rel_path})
+            endif()
+            list(APPEND pycfiles ${pygenfile}c)
+            list(APPEND pyofiles ${pygenfile}o)
 
-            get_filename_component(pycfile_path ${pycfile} PATH)
-            file(MAKE_DIRECTORY ${pycfile_path})
+            #ensure generation path exists
+            get_filename_component(pygen_path ${pygenfile} PATH)
+            file(MAKE_DIRECTORY ${pygen_path})
 
-            #create a command to generate the byte-compiled pyc file
-            add_custom_command(
-                OUTPUT ${pycfile} DEPENDS ${pyfile}
-                COMMAND ${PYTHON_EXECUTABLE} -c
-                \"import py_compile\; py_compile.compile(file='${pyfile}', cfile='${pycfile}', doraise=True)\"
-                COMMENT "Byte-compiling ${pyfile_name}"
-            )
-            install(FILES ${pycfile}
-                DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
-                COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
-            )
         endforeach(pyfile)
 
+        #the command to generate the pyc files
+        add_custom_command(
+            DEPENDS ${pysrcfiles} OUTPUT ${pycfiles}
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pycfiles}
+        )
+
+        #the command to generate the pyo files
+        add_custom_command(
+            DEPENDS ${pysrcfiles} OUTPUT ${pyofiles}
+            COMMAND ${PYTHON_EXECUTABLE} -O ${CMAKE_BINARY_DIR}/python_compile_helper.py ${pysrcfiles} ${pyofiles}
+        )
+
+        #create install rule and add generated files to target list
+        set(python_install_gen_targets ${pycfiles} ${pyofiles})
+        install(FILES ${python_install_gen_targets}
+            DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
+            COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
+        )
+
+
     ####################################################################
     elseif(GR_PYTHON_INSTALL_PROGRAMS)
     ####################################################################
@@ -175,3 +214,14 @@ function(GR_PYTHON_INSTALL)
     GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
 
 endfunction(GR_PYTHON_INSTALL)
+
+########################################################################
+# Write the python helper script that generates byte code files
+########################################################################
+file(WRITE ${CMAKE_BINARY_DIR}/python_compile_helper.py "
+import sys, py_compile
+files = sys.argv[1:]
+srcs, gens = files[:len(files)/2], files[len(files)/2:]
+for src, gen in zip(srcs, gens):
+    py_compile.compile(file=src, cfile=gen, doraise=True)
+")
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
index 0fa1c7b770..4be583aa15 100644
--- a/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
@@ -47,9 +47,19 @@ macro(GR_SWIG_MAKE name)
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
     )
 
+    #Create a dummy custom command that depends on other targets
+    include(GrMiscUtils)
+    GR_GEN_TARGET_DEPS(_${name}_swig_tag tag_deps ${GR_SWIG_TARGET_DEPS})
+    set(tag_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.tag)
+    add_custom_command(
+        OUTPUT ${tag_file}
+        DEPENDS ${GR_SWIG_SOURCE_DEPS} ${tag_deps}
+        COMMAND ${CMAKE_COMMAND} -E touch ${tag_file}
+    )
+
     #append the specified include directories
     include_directories(${GR_SWIG_INCLUDE_DIRS})
-    list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${GR_SWIG_SOURCE_DEPS})
+    list(APPEND SWIG_MODULE_${name}_EXTRA_DEPS ${tag_file})
 
     find_package(PythonLibs)
     include_directories(${PYTHON_INCLUDE_DIRS})
@@ -67,9 +77,6 @@ macro(GR_SWIG_MAKE name)
     include(UseSWIG)
     SWIG_ADD_MODULE(${name} python ${ifiles})
     SWIG_LINK_LIBRARIES(${name} ${PYTHON_LIBRARIES} ${GR_SWIG_LIBRARIES})
-    if(GR_SWIG_TARGET_DEPS)
-        add_dependencies(${SWIG_MODULE_${name}_REAL_NAME} ${GR_SWIG_TARGET_DEPS})
-    endif(GR_SWIG_TARGET_DEPS)
 
 endmacro(GR_SWIG_MAKE)
 
@@ -97,6 +104,12 @@ macro(GR_SWIG_INSTALL)
             DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
             COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
         )
+
+        GR_LIBTOOL(
+            TARGET ${SWIG_MODULE_${name}_REAL_NAME}
+            DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
+        )
+
     endforeach(name)
 
 endmacro(GR_SWIG_INSTALL)
-- 
cgit v1.2.3