From 626018eb037808cdc32b5eb1907ae9d5f80d3e55 Mon Sep 17 00:00:00 2001
From: Josh Blum
Date: Thu, 4 Aug 2011 10:33:49 -0700
Subject: cmake: re-imagining of how to write a block w/ cmake and boost unit
 test

---
 .../cmake/Modules/CMakeParseArgumentsCopy.cmake    | 138 ++++++++++++++++
 .../cmake/Modules/FindGnuradioCore.cmake           |  26 +++
 .../cmake/Modules/FindGruel.cmake                  |  26 +++
 .../cmake/Modules/GrPlatform.cmake                 |  46 ++++++
 .../cmake/Modules/GrPython.cmake                   | 177 +++++++++++++++++++++
 .../cmake/Modules/GrSwig.cmake                     |  90 +++++++++++
 .../cmake/Modules/GrTest.cmake                     | 133 ++++++++++++++++
 7 files changed, 636 insertions(+)
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/CMakeParseArgumentsCopy.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/FindGnuradioCore.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/FindGruel.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/GrPlatform.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
 create mode 100644 gr-howto-write-a-block-cmake/cmake/Modules/GrTest.cmake

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

diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/CMakeParseArgumentsCopy.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/CMakeParseArgumentsCopy.cmake
new file mode 100644
index 000000000..7ce4c49ae
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/CMakeParseArgumentsCopy.cmake
@@ -0,0 +1,138 @@
+# CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
+#
+# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for
+# parsing the arguments given to that macro or function.
+# It processes the arguments and defines a set of variables which hold the
+# values of the respective options.
+#
+# The <options> argument contains all options for the respective macro,
+# i.e. keywords which can be used when calling the macro without any value
+# following, like e.g. the OPTIONAL keyword of the install() command.
+#
+# The <one_value_keywords> argument contains all keywords for this macro
+# which are followed by one value, like e.g. DESTINATION keyword of the
+# install() command.
+#
+# The <multi_value_keywords> argument contains all keywords for this macro
+# which can be followed by more than one value, like e.g. the TARGETS or
+# FILES keywords of the install() command.
+#
+# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the
+# keywords listed in <options>, <one_value_keywords> and
+# <multi_value_keywords> a variable composed of the given <prefix>
+# followed by "_" and the name of the respective keyword.
+# These variables will then hold the respective value from the argument list.
+# For the <options> keywords this will be TRUE or FALSE.
+#
+# All remaining arguments are collected in a variable
+# <prefix>_UNPARSED_ARGUMENTS, this can be checked afterwards to see whether
+# your macro was called with unrecognized parameters.
+#
+# As an example here a my_install() macro, which takes similar arguments as the
+# real install() command:
+#
+#   function(MY_INSTALL)
+#     set(options OPTIONAL FAST)
+#     set(oneValueArgs DESTINATION RENAME)
+#     set(multiValueArgs TARGETS CONFIGURATIONS)
+#     cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+#     ...
+#
+# Assume my_install() has been called like this:
+#   my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub)
+#
+# After the cmake_parse_arguments() call the macro will have set the following
+# variables:
+#   MY_INSTALL_OPTIONAL = TRUE
+#   MY_INSTALL_FAST = FALSE (this option was not used when calling my_install()
+#   MY_INSTALL_DESTINATION = "bin"
+#   MY_INSTALL_RENAME = "" (was not used)
+#   MY_INSTALL_TARGETS = "foo;bar"
+#   MY_INSTALL_CONFIGURATIONS = "" (was not used)
+#   MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL"
+#
+# You can the continue and process these variables.
+#
+# Keywords terminate lists of values, e.g. if directly after a one_value_keyword
+# another recognized keyword follows, this is interpreted as the beginning of
+# the new option.
+# E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in
+# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would
+# be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor.
+
+#=============================================================================
+# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+
+if(__CMAKE_PARSE_ARGUMENTS_INCLUDED)
+  return()
+endif()
+set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE)
+
+
+function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames)
+  # first set all result variables to empty/FALSE
+  foreach(arg_name ${_singleArgNames} ${_multiArgNames})
+    set(${prefix}_${arg_name})
+  endforeach(arg_name)
+
+  foreach(option ${_optionNames})
+    set(${prefix}_${option} FALSE)
+  endforeach(option)
+
+  set(${prefix}_UNPARSED_ARGUMENTS)
+
+  set(insideValues FALSE)
+  set(currentArgName)
+
+  # now iterate over all arguments and fill the result variables
+  foreach(currentArg ${ARGN})
+    list(FIND _optionNames "${currentArg}" optionIndex)  # ... then this marks the end of the arguments belonging to this keyword
+    list(FIND _singleArgNames "${currentArg}" singleArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
+    list(FIND _multiArgNames "${currentArg}" multiArgIndex)  # ... then this marks the end of the arguments belonging to this keyword
+
+    if(${optionIndex} EQUAL -1  AND  ${singleArgIndex} EQUAL -1  AND  ${multiArgIndex} EQUAL -1)
+      if(insideValues)
+        if("${insideValues}" STREQUAL "SINGLE")
+          set(${prefix}_${currentArgName} ${currentArg})
+          set(insideValues FALSE)
+        elseif("${insideValues}" STREQUAL "MULTI")
+          list(APPEND ${prefix}_${currentArgName} ${currentArg})
+        endif()
+      else(insideValues)
+        list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg})
+      endif(insideValues)
+    else()
+      if(NOT ${optionIndex} EQUAL -1)
+        set(${prefix}_${currentArg} TRUE)
+        set(insideValues FALSE)
+      elseif(NOT ${singleArgIndex} EQUAL -1)
+        set(currentArgName ${currentArg})
+        set(${prefix}_${currentArgName})
+        set(insideValues "SINGLE")
+      elseif(NOT ${multiArgIndex} EQUAL -1)
+        set(currentArgName ${currentArg})
+        set(${prefix}_${currentArgName})
+        set(insideValues "MULTI")
+      endif()
+    endif()
+
+  endforeach(currentArg)
+
+  # propagate the result variables to the caller:
+  foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames})
+    set(${prefix}_${arg_name}  ${${prefix}_${arg_name}} PARENT_SCOPE)
+  endforeach(arg_name)
+  set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE)
+
+endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/FindGnuradioCore.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/FindGnuradioCore.cmake
new file mode 100644
index 000000000..f76364acf
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/FindGnuradioCore.cmake
@@ -0,0 +1,26 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(GNURADIO_CORE gnuradio-core)
+IF(NOT GNURADIO_CORE_FOUND)
+
+FIND_PATH(
+    GNURADIO_CORE_INCLUDE_DIRS
+    NAMES gr_random.h
+    HINTS $ENV{GNURADIO_CORE_DIR}/include/gnuradio
+    PATHS /usr/local/include/gnuradio
+          /usr/include/gnuradio
+)
+
+FIND_LIBRARY(
+    GNURADIO_CORE_LIBRARIES
+    NAMES gnuradio-core
+    HINTS $ENV{GNURADIO_CORE_DIR}/lib
+    PATHS /usr/local/lib
+          /usr/local/lib64
+          /usr/lib
+          /usr/lib64
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GNURADIO_CORE DEFAULT_MSG GNURADIO_CORE_LIBRARIES GNURADIO_CORE_INCLUDE_DIRS)
+
+ENDIF(NOT GNURADIO_CORE_FOUND)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/FindGruel.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/FindGruel.cmake
new file mode 100644
index 000000000..c142c905e
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/FindGruel.cmake
@@ -0,0 +1,26 @@
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(GRUEL gnuradio-core)
+IF(NOT GRUEL_FOUND)
+
+FIND_PATH(
+    GRUEL_INCLUDE_DIRS
+    NAMES gruel/attributes.h
+    HINTS $ENV{GRUEL_DIR}/include
+    PATHS /usr/local/include
+          /usr/include
+)
+
+FIND_LIBRARY(
+    GRUEL_LIBRARIES
+    NAMES gruel
+    HINTS $ENV{GRUEL_DIR}/lib
+    PATHS /usr/local/lib
+          /usr/local/lib64
+          /usr/lib
+          /usr/lib64
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GRUEL DEFAULT_MSG GRUEL_LIBRARIES GRUEL_INCLUDE_DIRS)
+
+ENDIF(NOT GRUEL_FOUND)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrPlatform.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrPlatform.cmake
new file mode 100644
index 000000000..85f318618
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrPlatform.cmake
@@ -0,0 +1,46 @@
+# Copyright 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_PLATFORM_CMAKE)
+    RETURN()
+ENDIF()
+SET(__INCLUDED_GR_PLATFORM_CMAKE TRUE)
+
+########################################################################
+# Setup additional defines for OS types
+########################################################################
+IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    SET(LINUX TRUE)
+ENDIF()
+
+IF(LINUX AND EXISTS "/etc/debian_version")
+    SET(DEBIAN TRUE)
+ENDIF()
+
+IF(LINUX AND EXISTS "/etc/redhat-release")
+    SET(REDHAT TRUE)
+ENDIF()
+
+########################################################################
+# when the library suffix should be 64 (applies to redhat linux family)
+########################################################################
+IF(NOT DEFINED LIB_SUFFIX AND REDHAT AND CMAKE_SYSTEM_PROCESSOR MATCHES "64$")
+    SET(LIB_SUFFIX 64)
+ENDIF()
+SET(LIB_SUFFIX ${LIB_SUFFIX} CACHE STRING "lib directory suffix")
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
new file mode 100644
index 000000000..f54dbc9ba
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrPython.cmake
@@ -0,0 +1,177 @@
+# 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_PYTHON_CMAKE)
+    RETURN()
+ENDIF()
+SET(__INCLUDED_GR_PYTHON_CMAKE TRUE)
+
+########################################################################
+# Setup the python interpreter:
+# This allows the user to specify a specific interpreter,
+# or finds the interpreter via the built-in cmake module.
+########################################################################
+#this allows the user to override PYTHON_EXECUTABLE
+IF(PYTHON_EXECUTABLE)
+
+    SET(PYTHONINTERP_FOUND TRUE)
+
+#otherwise if not set, try to automatically find it
+ELSE(PYTHON_EXECUTABLE)
+
+    #use the built-in find script
+    FIND_PACKAGE(PythonInterp)
+
+    #and if that fails use the find program routine
+    IF(NOT PYTHONINTERP_FOUND)
+        FIND_PROGRAM(PYTHON_EXECUTABLE NAMES python python2.7 python2.6 python2.5)
+        IF(PYTHON_EXECUTABLE)
+            SET(PYTHONINTERP_FOUND TRUE)
+        ENDIF(PYTHON_EXECUTABLE)
+    ENDIF(NOT PYTHONINTERP_FOUND)
+
+ENDIF(PYTHON_EXECUTABLE)
+
+#make the path to the executable appear in the cmake gui
+SET(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} CACHE FILEPATH "python interpreter")
+
+########################################################################
+# Check for the existence of a python module:
+# - desc a string description of the check
+# - mod the name of the module to import
+# - cmd an additional command to run
+# - have the result variable to set
+########################################################################
+MACRO(GR_PYTHON_CHECK_MODULE desc mod cmd have)
+    MESSAGE(STATUS "")
+    MESSAGE(STATUS "Python checking for ${desc}")
+    EXECUTE_PROCESS(
+        COMMAND ${PYTHON_EXECUTABLE} -c "
+#########################################
+try: import ${mod}
+except: exit(-1)
+try: assert ${cmd}
+except: exit(-1)
+#########################################"
+        RESULT_VARIABLE ${have}
+    )
+    IF(${have} EQUAL 0)
+        MESSAGE(STATUS "Python checking for ${desc} - found")
+        SET(${have} TRUE)
+    ELSE(${have} EQUAL 0)
+        MESSAGE(STATUS "Python checking for ${desc} - not found")
+        SET(${have} FALSE)
+    ENDIF(${have} EQUAL 0)
+ENDMACRO(GR_PYTHON_CHECK_MODULE)
+
+########################################################################
+# Sets the python installation directory GR_PYTHON_DIR
+########################################################################
+EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "
+from distutils import sysconfig
+print sysconfig.get_python_lib(plat_specific=True, prefix='')
+" OUTPUT_VARIABLE GR_PYTHON_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+FILE(TO_CMAKE_PATH ${GR_PYTHON_DIR} GR_PYTHON_DIR)
+
+########################################################################
+# Create an always-built target with a unique name
+# Usage: GR_UNIQUE_TARGET(<description> <dependencies list>)
+########################################################################
+FUNCTION(GR_UNIQUE_TARGET desc)
+    FILE(RELATIVE_PATH reldir ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+    EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import re, hashlib
+unique = hashlib.md5('${reldir}${ARGN}').hexdigest()[:5]
+print(re.sub('\\W', '_', '${desc} ${reldir} ' + unique))"
+    OUTPUT_VARIABLE _target OUTPUT_STRIP_TRAILING_WHITESPACE)
+    ADD_CUSTOM_TARGET(${_target} ALL DEPENDS ${ARGN})
+ENDFUNCTION(GR_UNIQUE_TARGET)
+
+########################################################################
+# Install python sources (also builds and installs byte-compiled python)
+########################################################################
+FUNCTION(GR_PYTHON_INSTALL)
+    INCLUDE(CMakeParseArgumentsCopy)
+    CMAKE_PARSE_ARGUMENTS(GR_PYTHON_INSTALL "" "DESTINATION;COMPONENT" "FILES;PROGRAMS" ${ARGN})
+
+    ####################################################################
+    IF(GR_PYTHON_INSTALL_FILES)
+    ####################################################################
+        INSTALL(${ARGN}) #installs regular python files
+
+        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})
+
+            GET_FILENAME_COMPONENT(pycfile_path ${pycfile} PATH)
+            FILE(MAKE_DIRECTORY ${pycfile_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)
+
+    ####################################################################
+    ELSEIF(GR_PYTHON_INSTALL_PROGRAMS)
+    ####################################################################
+        FILE(TO_NATIVE_PATH ${PYTHON_EXECUTABLE} pyexe_native)
+
+        FOREACH(pyfile ${GR_PYTHON_INSTALL_PROGRAMS})
+            GET_FILENAME_COMPONENT(pyfile_name ${pyfile} NAME)
+            GET_FILENAME_COMPONENT(pyfile ${pyfile} ABSOLUTE)
+            STRING(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" pyexefile "${pyfile}.exe")
+            LIST(APPEND python_install_gen_targets ${pyexefile})
+
+            GET_FILENAME_COMPONENT(pyexefile_path ${pyexefile} PATH)
+            FILE(MAKE_DIRECTORY ${pyexefile_path})
+
+            ADD_CUSTOM_COMMAND(
+                OUTPUT ${pyexefile} DEPENDS ${pyfile}
+                COMMAND ${PYTHON_EXECUTABLE} -c
+                \"open('${pyexefile}', 'w').write('\#!${pyexe_native}\\n'+open('${pyfile}').read())\"
+                COMMENT "Shebangin ${pyfile_name}"
+            )
+
+            #on windows, python files need an extension to execute
+            GET_FILENAME_COMPONENT(pyfile_ext ${pyfile} EXT)
+            IF(WIN32 AND NOT pyfile_ext)
+                SET(pyfile_name "${pyfile_name}.py")
+            ENDIF()
+
+            INSTALL(PROGRAMS ${pyexefile} RENAME ${pyfile_name}
+                DESTINATION ${GR_PYTHON_INSTALL_DESTINATION}
+                COMPONENT ${GR_PYTHON_INSTALL_COMPONENT}
+            )
+        ENDFOREACH(pyfile)
+
+    ENDIF()
+
+    GR_UNIQUE_TARGET("pygen" ${python_install_gen_targets})
+
+ENDFUNCTION(GR_PYTHON_INSTALL)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
new file mode 100644
index 000000000..9fca29a4f
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrSwig.cmake
@@ -0,0 +1,90 @@
+# 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_SWIG_CMAKE)
+    RETURN()
+ENDIF()
+SET(__INCLUDED_GR_SWIG_CMAKE TRUE)
+
+########################################################################
+# Build a swig target for the common gnuradio use case. Usage:
+# GR_SWIG_MAKE(target ifile ifile ifile...)
+#
+# Set the following variables before calling:
+#   - GR_SWIG_FLAGS
+#   - GR_SWIG_INCLUDE_DIRS
+#   - GR_SWIG_LIBRARIES
+#   - GR_SWIG_SOURCE_DEPS
+#   - GR_SWIG_TARGET_DEPS
+########################################################################
+MACRO(GR_SWIG_MAKE name)
+    SET(ifiles ${ARGN})
+
+    INCLUDE_DIRECTORIES(${GR_SWIG_INCLUDE_DIRS})
+    SET(SWIG_MODULE_${name}_EXTRA_DEPS ${GR_SWIG_SOURCE_DEPS})
+
+    FIND_PACKAGE(PythonLibs)
+    INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS})
+
+    #setup the swig flags with flags and include directories
+    SET(CMAKE_SWIG_FLAGS -fvirtual -modern -keyword -w511 -module ${name} ${GR_SWIG_FLAGS})
+    FOREACH(dir ${GR_SWIG_INCLUDE_DIRS})
+        LIST(APPEND CMAKE_SWIG_FLAGS "-I${dir}")
+    ENDFOREACH(dir)
+
+    #set the C++ property on the swig .i file so it builds
+    SET_SOURCE_FILES_PROPERTIES(${ifiles} PROPERTIES CPLUSPLUS ON)
+
+    #setup the actual swig library target to be built
+    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)
+
+########################################################################
+# Install swig targets generated by GR_SWIG_MAKE. Usage:
+# GR_SWIG_INSTALL(
+#   TARGETS target target target...
+#   [DESTINATION destination]
+#   [COMPONENT component]
+# )
+########################################################################
+MACRO(GR_SWIG_INSTALL)
+
+    INCLUDE(CMakeParseArgumentsCopy)
+    CMAKE_PARSE_ARGUMENTS(GR_SWIG_INSTALL "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
+
+    FOREACH(name ${GR_SWIG_INSTALL_TARGETS})
+        INSTALL(TARGETS ${SWIG_MODULE_${name}_REAL_NAME}
+            DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
+            COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
+        )
+
+        INCLUDE(GrPython)
+        GR_PYTHON_INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.py
+            DESTINATION ${GR_SWIG_INSTALL_DESTINATION}
+            COMPONENT ${GR_SWIG_INSTALL_COMPONENT}
+        )
+    ENDFOREACH(name)
+
+ENDMACRO(GR_SWIG_INSTALL)
diff --git a/gr-howto-write-a-block-cmake/cmake/Modules/GrTest.cmake b/gr-howto-write-a-block-cmake/cmake/Modules/GrTest.cmake
new file mode 100644
index 000000000..e9e2a0c2e
--- /dev/null
+++ b/gr-howto-write-a-block-cmake/cmake/Modules/GrTest.cmake
@@ -0,0 +1,133 @@
+# 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_TEST_CMAKE)
+    RETURN()
+ENDIF()
+SET(__INCLUDED_GR_TEST_CMAKE TRUE)
+
+########################################################################
+# Add a unit test and setup the environment for a unit test.
+# Takes the same arguments as the ADD_TEST function.
+#
+# Before calling set the following variables:
+# GR_TEST_TARGET_DEPS  - built targets for the library path
+# GR_TEST_LIBRARY_DIRS - directories for the library path
+# GR_TEST_PYTHON_DIRS  - directories for the python path
+########################################################################
+FUNCTION(GR_ADD_TEST test_name)
+
+    IF(WIN32)
+        #Ensure that the build exe also appears in the PATH.
+        LIST(APPEND GR_TEST_TARGET_DEPS ${ARGN})
+
+        #In the land of windows, all libraries must be in the PATH.
+        #Since the dependent libraries are not yet installed,
+        #we must manually set them in the PATH to run tests.
+        #The following appends the path of a target dependency.
+        FOREACH(target ${GR_TEST_TARGET_DEPS})
+            GET_TARGET_PROPERTY(location ${target} LOCATION)
+            IF(location)
+                GET_FILENAME_COMPONENT(path ${location} PATH)
+                STRING(REGEX REPLACE "\\$\\(.*\\)" ${CMAKE_BUILD_TYPE} path ${path})
+                LIST(APPEND GR_TEST_LIBRARY_DIRS ${path})
+            ENDIF(location)
+        ENDFOREACH(target)
+
+        #SWIG generates the python library files into a subdirectory.
+        #Therefore, we must append this subdirectory into PYTHONPATH.
+        #Only do this for the python directories matching the following:
+        FOREACH(pydir ${GR_TEST_PYTHON_DIRS})
+            GET_FILENAME_COMPONENT(name ${pydir} NAME)
+            IF(name MATCHES "^(swig|lib|src)$")
+                LIST(APPEND GR_TEST_PYTHON_DIRS ${pydir}/${CMAKE_BUILD_TYPE})
+            ENDIF()
+        ENDFOREACH(pydir)
+    ENDIF(WIN32)
+
+    FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} srcdir)
+    FILE(TO_NATIVE_PATH "${GR_TEST_LIBRARY_DIRS}" libpath) #ok to use on dir list?
+    FILE(TO_NATIVE_PATH "${GR_TEST_PYTHON_DIRS}" pypath) #ok to use on dir list?
+
+    SET(environs "GR_DONT_LOAD_PREFS=1" "srcdir=${srcdir}")
+
+    #http://www.cmake.org/pipermail/cmake/2009-May/029464.html
+    #Replaced this add test + set environs code with the shell script generation.
+    #Its nicer to be able to manually run the shell script to diagnose problems.
+    #ADD_TEST(${ARGV})
+    #SET_TESTS_PROPERTIES(${test_name} PROPERTIES ENVIRONMENT "${environs}")
+
+    IF(UNIX)
+        SET(binpath "${CMAKE_CURRENT_BINARY_DIR}:$PATH")
+        #set both LD and DYLD paths to cover multiple UNIX OS library paths
+        LIST(APPEND libpath "$LD_LIBRARY_PATH" "$DYLD_LIBRARY_PATH")
+        LIST(APPEND pypath "$PYTHONPATH")
+
+        #replace list separator with the path separator
+        STRING(REPLACE ";" ":" libpath "${libpath}")
+        STRING(REPLACE ";" ":" pypath "${pypath}")
+        LIST(APPEND environs "PATH=${binpath}" "LD_LIBRARY_PATH=${libpath}" "DYLD_LIBRARY_PATH=${libpath}" "PYTHONPATH=${pypath}")
+
+        #generate a bat file that sets the environment and runs the test
+        FIND_PROGRAM(SHELL sh)
+        SET(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
+        FILE(WRITE ${sh_file} "#!${SHELL}\n")
+        #each line sets an environment variable
+        FOREACH(environ ${environs})
+            FILE(APPEND ${sh_file} "export ${environ}\n")
+        ENDFOREACH(environ)
+        #load the command to run with its arguments
+        FOREACH(arg ${ARGN})
+            FILE(APPEND ${sh_file} "${arg} ")
+        ENDFOREACH(arg)
+        FILE(APPEND ${sh_file} "\n")
+
+        #make the shell file executable
+        EXECUTE_PROCESS(COMMAND chmod +x ${sh_file})
+
+        ADD_TEST(${test_name} ${SHELL} ${sh_file})
+
+    ENDIF(UNIX)
+
+    IF(WIN32)
+        LIST(APPEND libpath ${DLL_PATHS} "%PATH%")
+        LIST(APPEND pypath "%PYTHONPATH%")
+
+        #replace list separator with the path separator (escaped)
+        STRING(REPLACE ";" "\\;" libpath "${libpath}")
+        STRING(REPLACE ";" "\\;" pypath "${pypath}")
+        LIST(APPEND environs "PATH=${libpath}" "PYTHONPATH=${pypath}")
+
+        #generate a bat file that sets the environment and runs the test
+        SET(bat_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.bat)
+        FILE(WRITE ${bat_file} "@echo off\n")
+        #each line sets an environment variable
+        FOREACH(environ ${environs})
+            FILE(APPEND ${bat_file} "SET ${environ}\n")
+        ENDFOREACH(environ)
+        #load the command to run with its arguments
+        FOREACH(arg ${ARGN})
+            FILE(APPEND ${bat_file} "${arg} ")
+        ENDFOREACH(arg)
+        FILE(APPEND ${bat_file} "\n")
+
+        ADD_TEST(${test_name} ${bat_file})
+    ENDIF(WIN32)
+
+ENDFUNCTION(GR_ADD_TEST)
-- 
cgit