diff --git a/.travis.yml b/.travis.yml index 83d3eaf810..32064592a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -102,6 +102,7 @@ install: - "mkdir -p $TRAVIS_BUILD_DIR/build/scripts" - "cd $TRAVIS_BUILD_DIR/build/scripts" - "mkdir -p $TRAVIS_BUILD_DIR/build/release" + - "cmake --version" # Enable test coverage for travis-ci build - "cmake $TRAVIS_BUILD_DIR -DNTA_COV_ENABLED=ON -DCMAKE_INSTALL_PREFIX=${TRAVIS_BUILD_DIR}/build/release -DPY_EXTENSIONS_DIR=$TRAVIS_BUILD_DIR/bindings/py/nupic/bindings" # Configure bash such that a failure in any link in the pipe causes the whole pipe to fail diff --git a/CMakeLists.txt b/CMakeLists.txt index 37b536b941..89088d6ec5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,9 +46,12 @@ endif() # # Global NuPIC CMake options # -option(NUPIC_BUILD_PYEXT_MODULES "Turn on building of python extension modules for nupic.bindings" +option(NUPIC_BUILD_PYEXT_MODULES + "Turn on building of python extension modules for nupic.bindings; turn off to build only static nupic_core lib with full symbol visibility." ON) +message(STATUS "NUPIC_BUILD_PYEXT_MODULES = ${NUPIC_BUILD_PYEXT_MODULES}") + # # Identify build type - local or deployment (Travis) # the variable NUPIC_DEPLOYMENT_BUILD must be set in travis CI scripts @@ -77,18 +80,8 @@ set(EP_BASE ${CMAKE_BINARY_DIR}/ThirdParty) # Determine common toolchain settings, compiler and link flags include(CommonCompilerConfig) -# Set up external dependencies. -# -# This will try find_library and find_program and if that fails use -# ExternalProject to fetch and build the libraries. -# -# Sets the following variables: -# CAPNP_LINK_LIBRARIES -# EXTERNAL_INCLUDE_DIRS -# -# Defines the follow functions: -# create_capnpc_target - Creates target that generates C++ files from -# .capnp schema files. +# Set up builds of external dependencies and get their exports. +# (see individual external/*.cmake modules for exported settings and functions) add_subdirectory(external) include_directories(SYSTEM ${EXTERNAL_INCLUDE_DIRS}) diff --git a/CommonCompilerConfig.cmake b/CommonCompilerConfig.cmake index b463f25720..4264511398 100644 --- a/CommonCompilerConfig.cmake +++ b/CommonCompilerConfig.cmake @@ -316,6 +316,7 @@ IF(UNIX AND CMAKE_COMPILER_IS_GNUCXX AND (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "De list(APPEND EXTERNAL_STATICLIB_CMAKE_DEFINITIONS_OPTIMIZED -DCMAKE_AR:PATH=gcc-ar -DCMAKE_RANLIB:PATH=gcc-ranlib) + # And ditto for externals that use the configure-based build system list(APPEND EXTERNAL_STATICLIB_CONFIGURE_DEFINITIONS_OPTIMIZED AR=gcc-ar RANLIB=gcc-ranlib) diff --git a/appveyor.yml b/appveyor.yml index 27ebe261d4..1cacc2a4aa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -166,7 +166,6 @@ install: -DPY_EXTENSIONS_DIR=%NUPIC_CORE%\bindings\py\nupic\bindings %NUPIC_CORE% - build_script: - cd %NUPIC_CORE%\build\scripts diff --git a/external/Apr1Lib.cmake b/external/Apr1Lib.cmake index 4b8a837fda..57d2554cc1 100644 --- a/external/Apr1Lib.cmake +++ b/external/Apr1Lib.cmake @@ -22,18 +22,28 @@ # Creates ExternalProject for building the apr-1 static library # (apache public runtime) # -# Exports: -# LIB_STATIC_APR1_INC_DIR: directory of installed apr-1 lib headers -# LIB_STATIC_APR1_LOC: path to installed static apr-1 lib +# OUTPUT VARIABLES: +# +# APR1_STATIC_LIB_TARGET: name of static library target that contains all +# of the apr-1 library objects. +# APR1_STATIC_LIB_INC_DIR: directory of installed apr-1 lib headers + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + + +# Output static library target for linking and dependencies +set(APR1_STATIC_LIB_TARGET apr-1-bundle) + set(aprlib_install_prefix "${EP_BASE}/Install/Apr1StaticLib") set(aprlib_install_lib_dir "${aprlib_install_prefix}/lib") # Export directory of installed apr-1 lib headers -set(LIB_STATIC_APR1_INC_DIR "${aprlib_install_prefix}/include") +set(APR1_STATIC_LIB_INC_DIR "${aprlib_install_prefix}/include") -# Export path to installed static apr-1 lib -set(LIB_STATIC_APR1_LOC "${aprlib_install_lib_dir}/${STATIC_PRE}apr-1${STATIC_SUF}") +# Path to static apr-1 lib installed by external project +set(aprlib_built_archive_file + "${aprlib_install_lib_dir}/${STATIC_PRE}apr-1${STATIC_SUF}") # NOTE -DCOM_NO_WINDOWS_H fixes a bunch of OLE-related build errors on Win32 # (reference: https://bz.apache.org/bugzilla/show_bug.cgi?id=56342) @@ -109,18 +119,21 @@ else() ALWAYS 0 #LOG 1 - # Move the installed ${LIB_STATIC_APR1_INC_DIR}/*.h to - # ${LIB_STATIC_APR1_INC_DIR}/apr-1 + # Move the installed ${APR1_STATIC_LIB_INC_DIR}/*.h to + # ${APR1_STATIC_LIB_INC_DIR}/apr-1 COMMAND - ${CMAKE_COMMAND} -DGLOBBING_EXPR=${LIB_STATIC_APR1_INC_DIR}/*.h - -DDEST_DIR_PATH=${LIB_STATIC_APR1_INC_DIR}/apr-1 + ${CMAKE_COMMAND} -DGLOBBING_EXPR=${APR1_STATIC_LIB_INC_DIR}/*.h + -DDEST_DIR_PATH=${APR1_STATIC_LIB_INC_DIR}/apr-1 -P ${CMAKE_SOURCE_DIR}/external/MoveFilesToNewDir.cmake - # Copy /include/arch to ${LIB_STATIC_APR1_INC_DIR}/apr-1 as + # Copy /include/arch to ${APR1_STATIC_LIB_INC_DIR}/apr-1 as # expected by nupic.core COMMAND - ${CMAKE_COMMAND} -E make_directory ${LIB_STATIC_APR1_INC_DIR}/apr-1/arch + ${CMAKE_COMMAND} -E make_directory + ${APR1_STATIC_LIB_INC_DIR}/apr-1/arch COMMAND - ${CMAKE_COMMAND} -E copy_directory /include/arch ${LIB_STATIC_APR1_INC_DIR}/apr-1/arch + ${CMAKE_COMMAND} -E copy_directory + /include/arch + ${APR1_STATIC_LIB_INC_DIR}/apr-1/arch ) endif() @@ -143,3 +156,9 @@ ExternalProject_Add_Step(Apr1StaticLib patch_sources COMMAND patch -f -p1 --directory= --input=${aprlib_patch_file} ) + + +# Wrap external project-generated static library in an `add_library` target. +merge_static_libraries(${APR1_STATIC_LIB_TARGET} + ${aprlib_built_archive_file}) +add_dependencies(${APR1_STATIC_LIB_TARGET} Apr1StaticLib) diff --git a/external/AprUtil1Lib.cmake b/external/AprUtil1Lib.cmake index d604c5128c..2a388519fb 100644 --- a/external/AprUtil1Lib.cmake +++ b/external/AprUtil1Lib.cmake @@ -22,30 +22,40 @@ # Creates ExternalProject for building the aprutil-1 static library # (apache public runtime utilities) # -# Exports: -# LIB_STATIC_APRUTIL1_INC_DIR: directory of installed aprutil-1 lib headers -# LIB_STATIC_APRUTIL1_LOC: path to installed static aprutil-1 lib +# OUTPUT VARIABLES: +# +# APRUTIL1_STATIC_LIB_TARGET: name of static library target that contains all +# of the aprutil-1 library objects. +# APRUTIL1_STATIC_LIB_INC_DIR: directory of installed aprutil-1 lib headers + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + + +# Output static library target for linking and dependencies +set(APRUTIL1_STATIC_LIB_TARGET aprutil-1-bundle) + set(aprutillib_install_prefix "${EP_BASE}/Install/AprUtil1StaticLib") set(aprutillib_install_lib_dir "${aprutillib_install_prefix}/lib") # Export directory of installed aprutil-1 lib headers to parent -set(LIB_STATIC_APRUTIL1_INC_DIR "${aprutillib_install_prefix}/include") +set(APRUTIL1_STATIC_LIB_INC_DIR "${aprutillib_install_prefix}/include") -# Export path to installed static aprutil-1 lib to parent -set(LIB_STATIC_APRUTIL1_LOC "${aprutillib_install_lib_dir}/${STATIC_PRE}aprutil-1${STATIC_SUF}") +# Path to static aprutil-1 lib installed by external project +set(aprutillib_built_archive_file + "${aprutillib_install_lib_dir}/${STATIC_PRE}aprutil-1${STATIC_SUF}") # NOTE -DCOM_NO_WINDOWS_H fixes a bunch of OLE-related build errors in apr-1 # on Win32 (reference: https://bz.apache.org/bugzilla/show_bug.cgi?id=56342) set(aprutillib_cflags "-DCOM_NO_WINDOWS_H -DAPR_DECLARE_STATIC") -set(aprutillib_cflags "${aprutillib_cflags} -I${LIB_STATIC_APR1_INC_DIR}/apr-1") +set(aprutillib_cflags "${aprutillib_cflags} -I${APR1_STATIC_LIB_INC_DIR}/apr-1") set(aprutillib_cflags "${EXTERNAL_C_FLAGS_OPTIMIZED} ${COMMON_COMPILER_DEFINITIONS_STR} ${aprutillib_cflags}") set(aprutillib_url "${REPOSITORY_DIR}/external/common/share/apr-util/unix/apr-util-1.5.4.tar.gz") if (UNIX) set(aprutillib_config_options - --disable-util-dso --with-apr=${LIB_STATIC_APR1_INC_DIR}/..) + --disable-util-dso --with-apr=${APR1_STATIC_LIB_INC_DIR}/..) ExternalProject_Add(AprUtil1StaticLib DEPENDS Apr1StaticLib @@ -91,8 +101,8 @@ else() -DCMAKE_INSTALL_PREFIX=${aprutillib_install_prefix} -DAPR_HAS_LDAP=OFF -DAPU_HAVE_ODBC=OFF - -DAPR_INCLUDE_DIR=${LIB_STATIC_APR1_INC_DIR}/apr-1 - -DAPR_LIBRARIES=${LIB_STATIC_APR1_LOC} + -DAPR_INCLUDE_DIR=${APR1_STATIC_LIB_INC_DIR}/apr-1 + -DAPR_LIBRARIES= -DINSTALL_PDB=OFF #LOG_INSTALL 1 @@ -112,11 +122,11 @@ else() ALWAYS 0 #LOG 1 - # Move the installed ${LIB_STATIC_APRUTIL1_INC_DIR}/*.h to - # ${LIB_STATIC_APRUTIL1_INC_DIR}/apr-1 + # Move the installed ${APRUTIL1_STATIC_LIB_INC_DIR}/*.h to + # ${APRUTIL1_STATIC_LIB_INC_DIR}/apr-1 COMMAND - ${CMAKE_COMMAND} -DGLOBBING_EXPR=${LIB_STATIC_APRUTIL1_INC_DIR}/*.h - -DDEST_DIR_PATH=${LIB_STATIC_APRUTIL1_INC_DIR}/apr-1 + ${CMAKE_COMMAND} -DGLOBBING_EXPR=${APRUTIL1_STATIC_LIB_INC_DIR}/*.h + -DDEST_DIR_PATH=${APRUTIL1_STATIC_LIB_INC_DIR}/apr-1 -P ${CMAKE_SOURCE_DIR}/external/MoveFilesToNewDir.cmake ) @@ -141,3 +151,9 @@ ExternalProject_Add_Step(AprUtil1StaticLib patch_sources COMMAND patch -f -p1 --directory= --input=${aprutillib_patch_file} ) + + +# Wrap external project-generated static library in an `add_library` target. +merge_static_libraries(${APRUTIL1_STATIC_LIB_TARGET} + ${aprutillib_built_archive_file}) +add_dependencies(${APRUTIL1_STATIC_LIB_TARGET} AprUtil1StaticLib) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 58458f4493..62d6d3b3df 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -45,32 +45,32 @@ include(CapnProto) include(Swig) include(Apr1Lib) -set(LIB_STATIC_APR1_LOC ${LIB_STATIC_APR1_LOC} PARENT_SCOPE) -set(LIB_STATIC_APR1_INC_DIR ${LIB_STATIC_APR1_INC_DIR} PARENT_SCOPE) +set(APR1_STATIC_LIB_TARGET ${APR1_STATIC_LIB_TARGET} PARENT_SCOPE) +set(APR1_STATIC_LIB_INC_DIR ${APR1_STATIC_LIB_INC_DIR} PARENT_SCOPE) list(APPEND EXTERNAL_INCLUDE_DIRS - ${LIB_STATIC_APR1_INC_DIR} - "${LIB_STATIC_APR1_INC_DIR}/apr-1" + ${APR1_STATIC_LIB_INC_DIR} + "${APR1_STATIC_LIB_INC_DIR}/apr-1" ) # AprUtil1Lib MUST be imported after Apr1Lib due to depencies on exported # properties include(AprUtil1Lib) -set(LIB_STATIC_APRUTIL1_LOC ${LIB_STATIC_APRUTIL1_LOC} PARENT_SCOPE) -set(LIB_STATIC_APRUTIL1_INC_DIR ${LIB_STATIC_APRUTIL1_INC_DIR} PARENT_SCOPE) -list(APPEND EXTERNAL_INCLUDE_DIRS ${LIB_STATIC_APRUTIL1_INC_DIR}) +set(APRUTIL1_STATIC_LIB_TARGET ${APRUTIL1_STATIC_LIB_TARGET} PARENT_SCOPE) +set(APRUTIL1_STATIC_LIB_INC_DIR ${APRUTIL1_STATIC_LIB_INC_DIR} PARENT_SCOPE) +list(APPEND EXTERNAL_INCLUDE_DIRS ${APRUTIL1_STATIC_LIB_INC_DIR}) include(YamlLib) -set(LIB_STATIC_YAML_LOC ${LIB_STATIC_YAML_LOC} PARENT_SCOPE) +set(YAML_STATIC_LIB_TARGET ${YAML_STATIC_LIB_TARGET} PARENT_SCOPE) include(YamlCppLib) -set(LIB_STATIC_YAML_CPP_LOC ${LIB_STATIC_YAML_CPP_LOC} PARENT_SCOPE) -set(LIB_STATIC_YAML_CPP_INC_DIR ${LIB_STATIC_YAML_CPP_INC_DIR} PARENT_SCOPE) -list(APPEND EXTERNAL_INCLUDE_DIRS ${LIB_STATIC_YAML_CPP_INC_DIR}) +set(YAML_CPP_STATIC_LIB_TARGET ${YAML_CPP_STATIC_LIB_TARGET} PARENT_SCOPE) +set(YAML_CPP_STATIC_LIB_INC_DIR ${YAML_CPP_STATIC_LIB_INC_DIR} PARENT_SCOPE) +list(APPEND EXTERNAL_INCLUDE_DIRS ${YAML_CPP_STATIC_LIB_INC_DIR}) include(Zlib) -set(LIB_STATIC_Z_LOC ${LIB_STATIC_Z_LOC} PARENT_SCOPE) -set(LIB_STATIC_Z_INC_DIR ${LIB_STATIC_Z_INC_DIR} PARENT_SCOPE) -list(APPEND EXTERNAL_INCLUDE_DIRS ${LIB_STATIC_Z_INC_DIR}) +set(Z_STATIC_LIB_TARGET ${Z_STATIC_LIB_TARGET} PARENT_SCOPE) +set(Z_STATIC_LIB_INC_DIR ${Z_STATIC_LIB_INC_DIR} PARENT_SCOPE) +list(APPEND EXTERNAL_INCLUDE_DIRS ${Z_STATIC_LIB_INC_DIR}) # Add vendored prebuilt library include paths. list(APPEND EXTERNAL_INCLUDE_DIRS diff --git a/external/CapnProto.cmake b/external/CapnProto.cmake index 59672c478c..be69e4eb27 100644 --- a/external/CapnProto.cmake +++ b/external/CapnProto.cmake @@ -21,23 +21,39 @@ # Build Cap'n Proto from source. # -# OUTPUTS +# OUTPUT VARIABLES: # -# CAPNP_LINK_LIBRARIES: list of capnproto libraries (paths) needed by apps for linking -# CAPNP_INCLUDE_DIRS -# CAPNP_EXECUTABLE -# CAPNPC_CXX_EXECUTABLE -# CAPNP_CMAKE_DEFINITIONS: informational; platform-specific cmake defintions used by capnproto build -# CAPNP_COMPILER_DEFINITIONS: list of -D compiler defintions needed by apps that -# are built against this library (e.g., -DCAPNP_LITE) +# CAPNP_STATIC_LIB_TARGET: name of static library target that contains all of +# capnproto library objects. +# +# CAPNP_INCLUDE_DIRS +# CAPNP_EXECUTABLE +# CAPNPC_CXX_EXECUTABLE +# CAPNP_CMAKE_DEFINITIONS: informational; platform-specific cmake defintions +# used by capnproto build +# CAPNP_COMPILER_DEFINITIONS: list of -D compiler defintions needed by apps +# that are built against this library (e.g., +# -DCAPNP_LITE) +# +# EXPORTED FUNCTIONS: +# +# CREATE_CAPNPC_COMMAND: Create a custom command that runs the capnp compiler. + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES -set(capnproto_lib_url "${REPOSITORY_DIR}/external/common/share/capnproto/capnproto-c++-0.5.3.tar.gz") -set(capnproto_win32_tools_url "${REPOSITORY_DIR}/external/common/share/capnproto/capnproto-c++-win32-0.5.3.zip") +# Output static library target for linking and dependencies +set(CAPNP_STATIC_LIB_TARGET capnp-bundle) + +set(capnp_lib_url + "${REPOSITORY_DIR}/external/common/share/capnproto/capnproto-c++-0.5.3.tar.gz") +set(capnp_win32_tools_url + "${REPOSITORY_DIR}/external/common/share/capnproto/capnproto-c++-win32-0.5.3.zip") + +set(capnp_lib_kj ${LIB_PRE}/${STATIC_PRE}kj${STATIC_SUF}) +set(capnp_lib_capnp ${LIB_PRE}/${STATIC_PRE}capnp${STATIC_SUF}) +set(capnp_lib_capnpc ${LIB_PRE}/${STATIC_PRE}capnpc${STATIC_SUF}) -set(capnproto_lib_kj ${LIB_PRE}/${STATIC_PRE}kj${STATIC_SUF}) -set(capnproto_lib_capnp ${LIB_PRE}/${STATIC_PRE}capnp${STATIC_SUF}) -set(capnproto_lib_capnpc ${LIB_PRE}/${STATIC_PRE}capnpc${STATIC_SUF}) set(CAPNP_INCLUDE_DIRS ${INCLUDE_PRE}) set(CAPNP_EXECUTABLE ${BIN_PRE}/capnp${CMAKE_EXECUTABLE_SUFFIX}) set(CAPNPC_CXX_EXECUTABLE ${BIN_PRE}/capnpc-c++${CMAKE_EXECUTABLE_SUFFIX}) @@ -50,10 +66,10 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(CAPNP_CMAKE_DEFINITIONS -DCAPNP_LITE=1 -DEXTERNAL_CAPNP=1 -DBUILD_TOOLS=OFF) # NOTE nupic.core's swig wraps depend on the macro CAPNP_LITE to have a value set(CAPNP_COMPILER_DEFINITIONS ${CAPNP_COMPILER_DEFINITIONS} -DCAPNP_LITE=1) - set(CAPNP_LINK_LIBRARIES ${capnproto_lib_capnp} ${capnproto_lib_kj}) + set(capnp_link_libraries ${capnp_lib_capnp} ${capnp_lib_kj}) else() set(CAPNP_CMAKE_DEFINITIONS -DCAPNP_LITE=0) - set(CAPNP_LINK_LIBRARIES ${capnproto_lib_capnpc} ${capnproto_lib_capnp} ${capnproto_lib_kj}) + set(capnp_link_libraries ${capnp_lib_capnpc} ${capnp_lib_capnp} ${capnp_lib_kj}) endif() @@ -68,7 +84,7 @@ set(capnp_linker_flags "${EXTERNAL_LINKER_FLAGS_UNOPTIMIZED}") message(STATUS "CapnProto CXX_FLAGS=${capnp_cxx_flags}") ExternalProject_Add(CapnProto - URL ${capnproto_lib_url} + URL ${capnp_lib_url} UPDATE_COMMAND "" @@ -83,13 +99,20 @@ ExternalProject_Add(CapnProto -DCMAKE_INSTALL_PREFIX=${EP_BASE}/Install ) + +# Merge capnproto-generated static libraries into a single static library. +# This creates an `add_library` static library target that serves as the +# abstraction to all of capnproto library objects +merge_static_libraries(${CAPNP_STATIC_LIB_TARGET} "${capnp_link_libraries}") +add_dependencies(${CAPNP_STATIC_LIB_TARGET} CapnProto) + + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # Install prebuilt Cap'n Proto compilers for Windows ExternalProject_Add(CapnProtoTools DEPENDS CapnProto - #URL https://capnproto.org/capnproto-c++-win32-0.5.3.zip - URL ${capnproto_win32_tools_url} + URL ${capnp_win32_tools_url} CONFIGURE_COMMAND "" BUILD_COMMAND @@ -101,23 +124,31 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") ) endif() + function(CREATE_CAPNPC_COMMAND - GROUP_NAME SPEC_FILES SRC_PREFIX INCLUDE_DIR TARGET_DIR OUTPUT_FILES) + SPEC_FILES SRC_PREFIX INCLUDE_DIR TARGET_DIR OUTPUT_FILES) + # Create a custom command that runs the capnp compiler on ${SPEC_FILES} and + # generates ${OUTPUT_FILES} in directory ${TARGET_DIR} + + set(dependencies ${SPEC_FILES} CapnProto) + + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + list(APPEND dependencies CapnProtoTools) + endif() + add_custom_command( OUTPUT ${OUTPUT_FILES} COMMAND ${CAPNP_EXECUTABLE} compile -o ${CAPNPC_CXX_EXECUTABLE}:${TARGET_DIR} --src-prefix ${SRC_PREFIX} -I ${INCLUDE_DIR} ${SPEC_FILES} - DEPENDS CapnProto + DEPENDS ${dependencies} COMMENT "Executing Cap'n Proto compiler" ) - - add_custom_target(${GROUP_NAME} ALL SOURCES ${SPEC_FILES}) endfunction(CREATE_CAPNPC_COMMAND) # Set the relevant variables in the parent scope. -set(CAPNP_LINK_LIBRARIES ${CAPNP_LINK_LIBRARIES} PARENT_SCOPE) +set(CAPNP_STATIC_LIB_TARGET ${CAPNP_STATIC_LIB_TARGET} PARENT_SCOPE) set(CAPNP_INCLUDE_DIRS ${CAPNP_INCLUDE_DIRS} PARENT_SCOPE) set(CAPNP_EXECUTABLE ${CAPNP_EXECUTABLE} PARENT_SCOPE) set(CAPNPC_CXX_EXECUTABLE ${CAPNPC_CXX_EXECUTABLE} PARENT_SCOPE) @@ -133,6 +164,3 @@ set(CAPNP_COMPILER_DEFINITIONS ${CAPNP_COMPILER_DEFINITIONS} PARENT_SCOPE) # install(DIRECTORY ${INCLUDE_DIR}/capnp # DESTINATION include/) #endforeach () -# -#install(FILES ${CAPNP_LINK_LIBRARIES} -# DESTINATION lib/) diff --git a/external/YamlCppLib.cmake b/external/YamlCppLib.cmake index cd6eaec932..c20cdffffb 100644 --- a/external/YamlCppLib.cmake +++ b/external/YamlCppLib.cmake @@ -21,19 +21,29 @@ # Creates ExternalProject for building the yaml-cpp static library # -# Exports: -# LIB_STATIC_YAML_CPP_INC_DIR: directory of installed yaml-cpp lib headers -# LIB_STATIC_YAML_CPP_LOC: path to installed static yaml-cpp lib +# OUTPUT VARIABLES: +# +# YAML_CPP_STATIC_LIB_TARGET: name of static library target that contains all +# of yaml-cpp library objects. +# YAML_CPP_STATIC_LIB_INC_DIR: directory of installed yaml-cpp lib headers + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + + +# Output static library target for linking and dependencies +set(YAML_CPP_STATIC_LIB_TARGET yaml-cpp-bundle) + set(yamlcpplib_url "${REPOSITORY_DIR}/external/common/share/yaml-cpp/yaml-cpp-release-0.3.0.tar.gz") set(yamlcpplib_install_prefix "${EP_BASE}/Install/YamlCppStaticLib") set(yamlcpplib_install_lib_dir "${yamlcpplib_install_prefix}/lib") # Export directory of installed yaml-cpp lib headers to parent -set(LIB_STATIC_YAML_CPP_INC_DIR "${yamlcpplib_install_prefix}/include") +set(YAML_CPP_STATIC_LIB_INC_DIR "${yamlcpplib_install_prefix}/include") -# Export path to installed static yaml-cpp to parent -set(LIB_STATIC_YAML_CPP_LOC "${yamlcpplib_install_lib_dir}/${STATIC_PRE}yaml-cpp${STATIC_SUF}") +# Path to static yaml-cpp installed by external project +set(yamlcpplib_built_archive_file + "${yamlcpplib_install_lib_dir}/${STATIC_PRE}yaml-cpp${STATIC_SUF}") set(c_flags "${EXTERNAL_C_FLAGS_OPTIMIZED} ${COMMON_COMPILER_DEFINITIONS_STR}") set(cxx_flags "${EXTERNAL_CXX_FLAGS_OPTIMIZED} ${COMMON_COMPILER_DEFINITIONS_STR}") @@ -56,3 +66,9 @@ ExternalProject_Add(YamlCppStaticLib -DCMAKE_INSTALL_PREFIX=${yamlcpplib_install_prefix} ${EXTERNAL_STATICLIB_CMAKE_DEFINITIONS_OPTIMIZED} ) + + +# Wrap external project-generated static library in an `add_library` target. +merge_static_libraries(${YAML_CPP_STATIC_LIB_TARGET} + "${yamlcpplib_built_archive_file}") +add_dependencies(${YAML_CPP_STATIC_LIB_TARGET} YamlCppStaticLib) diff --git a/external/YamlLib.cmake b/external/YamlLib.cmake index de1a1bdb40..7b2d782566 100644 --- a/external/YamlLib.cmake +++ b/external/YamlLib.cmake @@ -21,8 +21,16 @@ # Creates ExternalProject for building yaml lib static library # -# Exports: -# LIB_STATIC_YAML_LOC: path to installed static yaml lib +# OUTPUT VARIABLES: +# +# YAML_STATIC_LIB_TARGET: name of static library target that contains all +# of yaml library objects. + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + + +# Output static library target for linking and dependencies +set(YAML_STATIC_LIB_TARGET yaml-bundle) set(yamllib_url "${REPOSITORY_DIR}/external/common/share/yaml/yaml-0.1.5.tar.gz") @@ -30,8 +38,9 @@ set(yamllib_url "${REPOSITORY_DIR}/external/common/share/yaml/yaml-0.1.5.tar.gz" # NOTE Yaml lib doesn't have an install target and leaves artifacts in build dir set(yamllib_build_dir "${EP_BASE}/Build/YamlStaticLib") -# Export path to installed static yaml lib to parent -set(LIB_STATIC_YAML_LOC "${yamllib_build_dir}/${STATIC_PRE}yaml${STATIC_SUF}") +# Path to static yaml installed by external project +set(yamllib_built_archive_file + "${yamllib_build_dir}/${STATIC_PRE}yaml${STATIC_SUF}") set(c_flags "${EXTERNAL_C_FLAGS_OPTIMIZED} ${COMMON_COMPILER_DEFINITIONS_STR}") @@ -51,3 +60,9 @@ ExternalProject_Add(YamlStaticLib -DCMAKE_INSTALL_PREFIX=${yamllib_build_dir} ${EXTERNAL_STATICLIB_CMAKE_DEFINITIONS_OPTIMIZED} ) + + +# Wrap external project-generated static library in an `add_library` target. +merge_static_libraries(${YAML_STATIC_LIB_TARGET} + "${yamllib_built_archive_file}") +add_dependencies(${YAML_STATIC_LIB_TARGET} YamlStaticLib) diff --git a/external/Zlib.cmake b/external/Zlib.cmake index 7eb198efb5..4a18de89fb 100644 --- a/external/Zlib.cmake +++ b/external/Zlib.cmake @@ -21,9 +21,18 @@ # Creates ExternalProject for building z lib static library # -# Exports: -# LIB_STATIC_Z_INC_DIR: directory of installed z lib headers -# LIB_STATIC_Z_LOC: path to installed static z lib +# OUTPUT VARIABLES: +# +# Z_STATIC_LIB_TARGET: name of static library target that contains all +# of the z library objects. +# Z_STATIC_LIB_INC_DIR: directory of installed z lib headers + +include(../src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + + +# Output static library target for linking and dependencies +set(Z_STATIC_LIB_TARGET z-bundle) + set(zlib_url "${REPOSITORY_DIR}/external/common/share/zlib/zlib-1.2.8.tar.gz") set(zlib_source_dir "${REPOSITORY_DIR}/external/common/share/zlib/zlib-1.2.8") @@ -39,10 +48,11 @@ endif() # Export directory of installed z lib headers to parent -set(LIB_STATIC_Z_INC_DIR "${zlib_install_prefix}/include") +set(Z_STATIC_LIB_INC_DIR "${zlib_install_prefix}/include") -# Export path to installed static z lib to parent -set(LIB_STATIC_Z_LOC "${zlib_install_lib_dir}/${STATIC_PRE}${zlib_output_root}${STATIC_SUF}") +# Path to static z lib installed by external project +set(zlib_built_archive_file + "${zlib_install_lib_dir}/${STATIC_PRE}${zlib_output_root}${STATIC_SUF}") set(c_flags "${EXTERNAL_C_FLAGS_OPTIMIZED} ${COMMON_COMPILER_DEFINITIONS_STR}") @@ -62,9 +72,15 @@ ExternalProject_Add(ZStaticLib -DCMAKE_C_FLAGS=${c_flags} -DCMAKE_INSTALL_PREFIX=${zlib_install_prefix} -DINSTALL_BIN_DIR=${zlib_install_prefix}/bin - -DINSTALL_INC_DIR=${LIB_STATIC_Z_INC_DIR} + -DINSTALL_INC_DIR=${Z_STATIC_LIB_INC_DIR} -DINSTALL_LIB_DIR=${zlib_install_lib_dir} -DINSTALL_MAN_DIR=${zlib_install_prefix}/man -DINSTALL_PKGCONFIG_DIR=${zlib_install_prefix}/pkgconfig ${EXTERNAL_STATICLIB_CMAKE_DEFINITIONS_OPTIMIZED} ) + + +# Wrap external project-generated static library in an `add_library` target. +merge_static_libraries(${Z_STATIC_LIB_TARGET} + "${zlib_built_archive_file}") +add_dependencies(${Z_STATIC_LIB_TARGET} ZStaticLib) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1fb878af0..b052916601 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,13 +60,14 @@ endif() # set(src_compile_flags "${INTERNAL_CXX_FLAGS_OPTIMIZED}") -set(swig_generated_file_compile_flags "${EXTERNAL_CXX_FLAGS_OPTIMIZED}") +set(src_swig_generated_file_compile_flags "${EXTERNAL_CXX_FLAGS_OPTIMIZED}") if(MINGW) # This is for GCC 4.8.x # http://stackoverflow.com/questions/10660524/error-building-boost-1-49-0-with-gcc-4-7-0 set(src_compile_flags "${src_compile_flags} -include cmath") - set(swig_generated_file_compile_flags "${swig_generated_file_compile_flags} -include cmath") + set(src_swig_generated_file_compile_flags + "${src_swig_generated_file_compile_flags} -include cmath") endif() @@ -129,7 +130,7 @@ add_definitions(${src_compiler_definitions}) # And NumPy core directory # find_package(PythonInterp 2.7 REQUIRED) -message(STATUS "CMAKE Found python interpreter ${PYTHON_EXECUTABLE} version=%{PYTHON_VERSION_STRING}") +message(STATUS "CMAKE Found python interpreter ${PYTHON_EXECUTABLE} version=${PYTHON_VERSION_STRING}") execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "import numpy; import os; import sys; sys.stdout.write(os.path.dirname(numpy.get_include()))" OUTPUT_VARIABLE src_numpy_core) @@ -184,7 +185,7 @@ set_target_properties(${src_lib_static_gtest} LINK_FLAGS "${INTERNAL_LINKER_FLAGS_OPTIMIZED}") # -# Setup for python +# Locate Python artifacts # find_package(PythonLibs REQUIRED) include_directories(SYSTEM ${PYTHON_INCLUDE_DIRS}) @@ -193,6 +194,36 @@ message(STATUS "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}") message(STATUS "PYTHON_INCLUDE_DIRS = ${PYTHON_INCLUDE_DIRS}") message(STATUS "PYTHON_LIBRARIES = ${PYTHON_LIBRARIES}") + +# +# Python support +# +set(src_py_support_files + nupic/py_support/NumpyVector.cpp + nupic/py_support/PyArray.cpp + nupic/py_support/PyHelpers.cpp + nupic/py_support/PythonStream.cpp + nupic/py_support/PyCapnp.cpp + nupic/bindings/PySparseTensor.cpp +) + +# +# pycapnp integration +# +if(NOT "${PLATFORM}" STREQUAL "windows") + list(APPEND src_py_support_files nupic/py_support/CapnpToPycapnp.cpp) + + # Add the pycapnp Python package headers to includes + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" "-c" + "import capnp; import os; import sys; sys.stdout.write(os.path.dirname(os.path.dirname(capnp.__file__)))" + OUTPUT_VARIABLE src_pycapnp_include_dir) + + message(STATUS "src_pycapnp_include_dir = ${src_pycapnp_include_dir}") + include_directories(SYSTEM ${src_pycapnp_include_dir}) +endif() + + # List all .capnp files here. The C++ files will be generated and included # when compiling later on. set(src_capnp_specs_rel @@ -215,57 +246,34 @@ set(src_capnp_specs_rel nupic/proto/VectorFileSensorProto.capnp ) +# Create custom command for generating C++ code from .capnp schema files. + foreach(spec ${src_capnp_specs_rel}) list(APPEND src_capnp_specs ${PROJECT_SOURCE_DIR}/${spec}) - list(APPEND src_capnp_hdrs ${PROJECT_BINARY_DIR}/${spec}.h) - list(APPEND src_capnp_srcs ${PROJECT_BINARY_DIR}/${spec}.c++) + list(APPEND src_capnp_generated_hdrs ${PROJECT_BINARY_DIR}/${spec}.h) + list(APPEND src_capnp_generated_srcs ${PROJECT_BINARY_DIR}/${spec}.c++) endforeach(spec) -set(src_capnp_all_spec_hdrs_and_srcs "${src_capnp_hdrs};${src_capnp_srcs}") +set(src_capnp_all_spec_hdrs_and_srcs + ${src_capnp_generated_hdrs} + ${src_capnp_generated_srcs}) -# Create custom target for generating C++ code from .capnp schema files. -create_capnpc_command(capnp_specs - "${src_capnp_specs}" +create_capnpc_command("${src_capnp_specs}" ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} "${src_capnp_all_spec_hdrs_and_srcs}") -# -# Python support -# -set (src_py_support_files - nupic/py_support/NumpyVector.cpp - nupic/py_support/PyArray.cpp - nupic/py_support/PyHelpers.cpp - nupic/py_support/PythonStream.cpp - nupic/py_support/PyCapnp.cpp -) -if(NOT "${PLATFORM}" STREQUAL "windows") - list(APPEND src_py_support_files nupic/py_support/CapnpToPycapnp.cpp) -endif() message(STATUS "CAPNP_EXECUTABLE = ${CAPNP_EXECUTABLE}") message(STATUS "CAPNP_CMAKE_DEFINITIONS = ${CAPNP_CMAKE_DEFINITIONS}") message(STATUS "CAPNP_INCLUDE_DIRS = ${CAPNP_INCLUDE_DIRS}") -message(STATUS "CAPNP_LINK_LIBRARIES = ${CAPNP_LINK_LIBRARIES}") +message(STATUS "CAPNP_STATIC_LIB_TARGET = ${CAPNP_STATIC_LIB_TARGET}") -# -# Add the pycapnp Python package to includes -if(NOT "${PLATFORM}" STREQUAL "windows") - execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" - "import capnp; import os; import sys; sys.stdout.write(os.path.dirname(os.path.dirname(capnp.__file__)))" - OUTPUT_VARIABLE src_pycapnp_include_dir) - message(STATUS "src_pycapnp_include_dir = ${src_pycapnp_include_dir}") - include_directories(SYSTEM ${src_pycapnp_include_dir}) -endif() # -# Setup libnupic_core +# Common system libraries for shared libraries and executables # -set(src_lib_static_nupiccore_solo nupic_core_solo) - -set(src_common_libs - ${CAPNP_LINK_LIBRARIES}) +set(src_common_os_libs) if("${PLATFORM}" STREQUAL "linux") list(APPEND src_common_os_libs pthread dl) @@ -277,6 +285,18 @@ elseif("${PLATFORM}" STREQUAL "windows") list(APPEND src_common_os_libs oldnames.lib psapi.lib ws2_32.lib) endif() +message(STATUS "src_common_os_libs = ${src_common_os_libs}") + + +# +# Setup nupic_core_solo static library, consisting of our own sources; +# +# this is an intermediate archive that will be merged with external static +# libraries in a subsequent step to produce the nupic_core "combined" static +# library. +# +set(src_lib_static_nupiccore_solo nupic_core_solo) + set(src_nupiccore_srcs nupic/algorithms/Anomaly.cpp nupic/algorithms/BitHistory.cpp @@ -352,45 +372,27 @@ set(src_nupiccore_srcs nupic/utils/Watcher.cpp) set(src_lib_static_nupiccore_srcs - ${src_capnp_srcs} + ${src_capnp_generated_srcs} ${src_py_support_files} ${src_nupiccore_srcs}) -set(src_lib_static_nupiccore_solo_link_libs - ${LIB_STATIC_YAML_CPP_LOC} - ${LIB_STATIC_YAML_LOC} - ${LIB_STATIC_APR1_LOC} - ${LIB_STATIC_APRUTIL1_LOC} - ${LIB_STATIC_Z_LOC} - ${src_common_libs} - ${src_common_os_libs}) - set(src_lib_static_nupiccore_compile_flags "${src_compile_flags} -I${src_numpy_core}/include") -# TODO Does the static library nupiccore_solo need the flags from INTERNAL_LINKER_FLAGS_OPTIMIZED? -set(src_lib_static_nupiccore_link_flags - "${INTERNAL_LINKER_FLAGS_OPTIMIZED} -static") message(STATUS "src_compile_flags = ${src_compile_flags}") message(STATUS "src_lib_static_nupiccore_compile_flags = ${src_lib_static_nupiccore_compile_flags}") -message(STATUS "src_lib_static_nupiccore_link_flags = ${src_lib_static_nupiccore_link_flags}") -message(STATUS "src_lib_static_nupiccore_solo_link_libs = ${src_lib_static_nupiccore_solo_link_libs}") -add_library(${src_lib_static_nupiccore_solo} STATIC ${src_lib_static_nupiccore_srcs}) +add_library(${src_lib_static_nupiccore_solo} STATIC + ${src_lib_static_nupiccore_srcs}) +# nupic_core_solo sources depend on headers installed by these external projects add_dependencies(${src_lib_static_nupiccore_solo} - Apr1StaticLib - AprUtil1StaticLib - ZStaticLib - YamlStaticLib - YamlCppStaticLib -) - -target_link_libraries(${src_lib_static_nupiccore_solo} - ${src_lib_static_nupiccore_solo_link_libs}) + ${YAML_CPP_STATIC_LIB_TARGET} + ${YAML_STATIC_LIB_TARGET} + ${APR1_STATIC_LIB_TARGET} + ${APRUTIL1_STATIC_LIB_TARGET} + ${Z_STATIC_LIB_TARGET}) set_target_properties(${src_lib_static_nupiccore_solo} PROPERTIES COMPILE_FLAGS ${src_lib_static_nupiccore_compile_flags}) -set_target_properties(${src_lib_static_nupiccore_solo} PROPERTIES LINK_FLAGS - ${src_lib_static_nupiccore_link_flags}) if(${NUPIC_IWYU}) # TODO: Create a target that doesn't include the generated capnp schema files # since we don't want to run iwyu on them and iwyu can only be applied to @@ -399,12 +401,56 @@ if(${NUPIC_IWYU}) PROPERTIES CXX_INCLUDE_WHAT_YOU_USE ${iwyu_path}) endif() + +# +# Create the nupic_core "combined" static library by merging nupic_core_solo +# with our external static libraries +# + +include(src/NupicLibraryUtils) # for MERGE_STATIC_LIBRARIES + +set(src_lib_static_nupiccore_combined nupic_core) + +set(src_external_static_libs + ${YAML_CPP_STATIC_LIB_TARGET} + ${YAML_STATIC_LIB_TARGET} + ${APR1_STATIC_LIB_TARGET} + ${APRUTIL1_STATIC_LIB_TARGET} + ${Z_STATIC_LIB_TARGET}) + +# Add capnproto static lib when building nupic_core static lib without python +# extensions. The extensions have their own logic governing whether to include +# it. +if (NOT ${NUPIC_BUILD_PYEXT_MODULES}) + list(APPEND src_external_static_libs ${CAPNP_STATIC_LIB_TARGET}) +endif() # ${NUPIC_BUILD_PYEXT_MODULES} + +set(src_combined_nupiccore_source_archives + ${src_lib_static_nupiccore_solo} + ${src_external_static_libs}) + +# Create a top-level library target for the combined static lib +merge_static_libraries(${src_lib_static_nupiccore_combined} + "${src_combined_nupiccore_source_archives}") + + +# +# Build tests of the nupic_core "combined" static library +# + # Common libs for test executables set(src_common_test_exe_libs - ${src_lib_static_nupiccore_solo} - ${src_common_libs} + ${src_lib_static_nupiccore_combined} ${PYTHON_LIBRARIES} -) + ${src_common_os_libs}) + +# Add capnproto static lib to our C/C++ test apps when building python +# extensions, since capnproto objects are excluded from nupic_core combined lib +# to avoid conflict with capnproto methods compiled into the pycapnp extension +if (${NUPIC_BUILD_PYEXT_MODULES}) + list(APPEND src_common_test_exe_libs ${CAPNP_STATIC_LIB_TARGET}) +endif() # ${NUPIC_BUILD_PYEXT_MODULES} + # # Setup test_cpp_region @@ -417,6 +463,7 @@ set_target_properties(${src_executable_cppregiontest} PROPERTIES LINK_FLAGS "${I add_custom_target(tests_cpp_region COMMAND ${src_executable_cppregiontest} DEPENDS ${src_executable_cppregiontest} + COMMENT "Executing test ${src_executable_cppregiontest}" VERBATIM) # @@ -432,6 +479,7 @@ set_target_properties(${src_executable_pyregiontest} add_custom_target(tests_py_region COMMAND ${src_executable_pyregiontest} DEPENDS ${src_executable_pyregiontest} + COMMENT "Executing test ${src_executable_pyregiontest}" VERBATIM) # @@ -440,7 +488,8 @@ add_custom_target(tests_py_region set(src_executable_connectionsperformancetest connections_performance_test) add_executable(${src_executable_connectionsperformancetest} test/integration/ConnectionsPerformanceTest.cpp) -target_link_libraries(${src_executable_connectionsperformancetest} ${src_common_test_exe_libs}) +target_link_libraries(${src_executable_connectionsperformancetest} + ${src_common_test_exe_libs}) set_target_properties(${src_executable_connectionsperformancetest} PROPERTIES COMPILE_FLAGS ${src_compile_flags}) set_target_properties(${src_executable_connectionsperformancetest} @@ -448,6 +497,7 @@ set_target_properties(${src_executable_connectionsperformancetest} add_custom_target(tests_connections_performance COMMAND ${src_executable_connectionsperformancetest} DEPENDS ${src_executable_connectionsperformancetest} + COMMENT "Executing test ${src_executable_connectionsperformancetest}" VERBATIM) # @@ -460,7 +510,6 @@ set_target_properties(${src_executable_helloregion} PROPERTIES COMPILE_FLAGS ${src_compile_flags}) set_target_properties(${src_executable_helloregion} PROPERTIES LINK_FLAGS "${INTERNAL_LINKER_FLAGS_OPTIMIZED}") -add_dependencies(${src_executable_helloregion} ${src_common_test_exe_libs}) # # Setup prototest example @@ -472,7 +521,6 @@ set_target_properties(${src_executable_prototest} PROPERTIES COMPILE_FLAGS ${src_compile_flags}) set_target_properties(${src_executable_prototest} PROPERTIES LINK_FLAGS "${INTERNAL_LINKER_FLAGS_OPTIMIZED}") -add_dependencies(${src_executable_prototest} ${src_common_test_exe_libs}) # # Setup HelloSP_TP example @@ -484,7 +532,6 @@ set_target_properties(${src_executable_hellosptp} PROPERTIES COMPILE_FLAGS ${src_compile_flags}) set_target_properties(${src_executable_hellosptp} PROPERTIES LINK_FLAGS "${INTERNAL_LINKER_FLAGS_OPTIMIZED}") -add_dependencies(${src_executable_hellosptp} ${src_common_test_exe_libs}) # @@ -550,80 +597,34 @@ set_target_properties(${src_executable_gtests} add_custom_target(tests_unit COMMAND ${src_executable_gtests} DEPENDS ${src_executable_gtests} + COMMENT "Executing test ${src_executable_gtests}" VERBATIM) -add_dependencies(${src_executable_gtests} ${src_lib_static_gtest} ${src_common_test_exe_libs}) # # tests_all just calls other targets # +# TODO This doesn't seem to have any effect; it's probably because the DEPENDS +# of add_custom_target must be files, not other high-level targets. If really +# need to run these tests during build, then either the individual +# add_custom_target of the individual test runners should be declared with the +# ALL option, or tests_all target whould be declared without DEPENDS, and +# add_dependencies should be used to set it's dependencies on the custom targets +# of the inidividual test runners. add_custom_target(tests_all DEPENDS tests_cpp_region DEPENDS tests_unit COMMENT "Running all tests" VERBATIM) -# Dependencies of the combined nupic.core static lib -set(src_nupiccore_combined_deps - ${src_lib_static_nupiccore_solo} - Apr1StaticLib - AprUtil1StaticLib - ZStaticLib - YamlStaticLib - YamlCppStaticLib) - -if(UNIX OR MSYS OR MINGW) - set(src_lib_static_nupiccore_combined "${PROJECT_BINARY_DIR}/libnupic_core.a") - if(MSYS OR MINGW) - add_custom_command(OUTPUT ${src_lib_static_nupiccore_combined} - COMMAND ${CMAKE_AR} -x $ - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_YAML_CPP_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_YAML_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_APRUTIL1_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_APR1_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_Z_LOC} - COMMAND ${CMAKE_AR} rcs ${src_lib_static_nupiccore_combined} *.obj - DEPENDS ${src_nupiccore_combined_deps}) - else() - add_custom_command(OUTPUT ${src_lib_static_nupiccore_combined} - COMMAND ${CMAKE_AR} -x $ - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_YAML_CPP_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_YAML_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_APRUTIL1_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_APR1_LOC} - COMMAND ${CMAKE_AR} -x ${LIB_STATIC_Z_LOC} - COMMAND ${CMAKE_AR} rcs ${src_lib_static_nupiccore_combined} *.o - DEPENDS ${src_nupiccore_combined_deps}) - endif() -else() - set(src_lib_static_nupiccore_combined "${PROJECT_BINARY_DIR}/nupic_core.lib") - add_custom_command(OUTPUT ${src_lib_static_nupiccore_combined} - COMMAND lib.exe /OUT:${src_lib_static_nupiccore_combined} - $ - ${LIB_STATIC_YAML_CPP_LOC} - ${LIB_STATIC_YAML_LOC} - ${LIB_STATIC_APRUTIL1_LOC} - ${LIB_STATIC_APR1_LOC} - ${LIB_STATIC_Z_LOC} - DEPENDS ${src_nupiccore_combined_deps} - VERBATIM) -endif() - - -# Wrap nupic.core combined lib output in custom target to avoid conflict from -# other dependent targets that may execute in parallel. NOTE Other targets MUST -# use LibStaticNupicCoreCombinedTarget as a dependency instead of -# ${src_lib_static_nupiccore_combined} -add_custom_target(LibStaticNupicCoreCombinedTarget - DEPENDS ${src_lib_static_nupiccore_combined}) +# +# Use SWIG to generate Python extensions. +# if (${NUPIC_BUILD_PYEXT_MODULES}) - # - # Call SWIG to generate wrapper code for Python. - # include(UseSWIG) - message(STATUS "PYEXT_LINKER_FLAGS_OPTIMIZED = ${PYEXT_LINKER_FLAGS_OPTIMIZED}") message(STATUS "CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID}") + message(STATUS "PY_EXTENSIONS_DIR = ${PY_EXTENSIONS_DIR}") # Set the output location for the language modules that are created. set(CMAKE_SWIG_OUTDIR ${PROJECT_BINARY_DIR}) @@ -669,32 +670,73 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) # Tell swig which command-line options to use, allowing user to override set(CMAKE_SWIG_FLAGS ${src_swig_flags} ${CMAKE_SWIG_FLAGS}) - set(src_swig_support_files - nupic/py_support/NumpyVector.cpp - nupic/py_support/PyArray.cpp - nupic/py_support/PyHelpers.cpp - nupic/py_support/PythonStream.cpp - nupic/bindings/PySparseTensor.cpp - ) + # Set up linker flags for python extension shared libraries + set(src_swig_extension_link_flags "${PYEXT_LINKER_FLAGS_OPTIMIZED}") - # NOTE Python extensions shouldn't be linking agains libpython; symbols should - # be available automatically when python loads the extension. + # NOTE Non-Windows Python extensions shouldn't be linking agains libpython; + # symbols should be available automatically when python loads the extension. + # + # NOTE We don't link our non-Windows python extensions with capnproto static + # lib in order to force runtime linkage to pycapnp's capnproto symbols thus + # avoiding the conflict of executing the methods in our own + # compilation of capnproto (different compiler/STL/version, flags, etc.) on + # objects created by pycapnp's. We force runtime linking to pycapnp's + # capnproto symbols by preloading the pycapnp extension in our extension + # python proxy modules, thus avoiding the conflict from executing the methods + # in our own compilation of capnproto on objects created by pycapnp's. set(src_swig_link_libraries ${src_lib_static_nupiccore_combined} ${src_common_os_libs}) + # Common dependencies for our python extensions for use with + # SWIG_MODULE_name_EXTRA_DEPS + set(src_swig_extra_deps Swig) + + # NOTE Windows DLLs are shared executables with their own main; they require + # all symbols to resolve at link time, so we have to add libpython for this + # platform + # + # NOTE On Windows nupic.bindings builds, we include capnproto because we + # presently build self-contained CAPNP_LITE on Windows, and Windows + # nupic/nupic.bindings presently have no dependency on pycapnp. We also include + # PYTHON_LIBRARIES because all symbols have to resolve when building a DLL. if("${PLATFORM}" STREQUAL "windows") - # Windows DLLs are shared executables with their own main; they require - # all symbols to resolve at link time, so we have to add libpython for this - # platform - list(APPEND src_swig_link_libraries ${PYTHON_LIBRARIES}) + list(APPEND src_swig_link_libraries + ${PYTHON_LIBRARIES} + ${CAPNP_STATIC_LIB_TARGET}) endif() - set(src_swig_link_libraries - ${src_swig_link_libraries} - ${CAPNP_LINK_LIBRARIES}) - + message(STATUS "src_swig_extra_deps = ${src_swig_extra_deps}") message(STATUS "src_swig_link_libraries = ${src_swig_link_libraries}") + message(STATUS "src_swig_extension_link_flags= ${src_swig_extension_link_flags}") + message(STATUS "CMAKE_SWIG_FLAGS = ${CMAKE_SWIG_FLAGS}") + + + function(PREPEND_BOILERPLATE_TO_PYTHON_PROXY_MODULE + PARENT_SWIG_TARGET) + # Add a custom command to the given Swig target to prepend boilerplate to + # the swig-generated python proxy module + # ${CMAKE_SWIG_OUTDIR}/${PARENT_SWIG_TARGET}.py. The boilerplate preloads + # the pycapnp extension shared library on Unix platforms. + # + # :param PARENT_SWIG_TARGET: the custom command will be added to this + # swig_add_module target + set(preamble_filepath "${CMAKE_SOURCE_DIR}/src/nupic/bindings/swig_proxy_preamble.py") + set(module_filepath "${CMAKE_SWIG_OUTDIR}/${PARENT_SWIG_TARGET}.py") + + add_custom_command( + TARGET ${SWIG_MODULE_${PARENT_SWIG_TARGET}_REAL_NAME} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} + -DSRC_FILE_1=${preamble_filepath} + -DSRC_FILE_2=${module_filepath} + -DTARGET_FILE=${module_filepath} + -P ${CMAKE_SOURCE_DIR}/src/ConcatTwoFiles.cmake + COMMENT "Prepending ${preamble_filepath} to swig-generated module ${module_filepath}" + ) + endfunction(PREPEND_BOILERPLATE_TO_PYTHON_PROXY_MODULE) + # Algorithms set(src_swig_algorithms_files nupic/bindings/algorithms.i) @@ -703,16 +745,15 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) SWIG_MODULE_NAME algorithms) set(src_swig_algorithms algorithms) # Make sure we don't attempt to execute the swig executable until it is built. - set(SWIG_MODULE_${src_swig_algorithms}_EXTRA_DEPS Swig LibStaticNupicCoreCombinedTarget) + set(SWIG_MODULE_${src_swig_algorithms}_EXTRA_DEPS ${src_swig_extra_deps}) # Create custom command for generating files from SWIG. - swig_add_module(${src_swig_algorithms} python - ${src_swig_support_files} - ${src_swig_algorithms_files}) + swig_add_module(${src_swig_algorithms} python ${src_swig_algorithms_files}) list(APPEND src_swig_generated_files ${swig_generated_file_fullname}) swig_link_libraries(${src_swig_algorithms} ${src_swig_link_libraries}) set_target_properties(${SWIG_MODULE_${src_swig_algorithms}_REAL_NAME} PROPERTIES - LINK_FLAGS "${PYEXT_LINKER_FLAGS_OPTIMIZED}") + LINK_FLAGS "${src_swig_extension_link_flags}") + prepend_boilerplate_to_python_proxy_module(${src_swig_algorithms}) # Engine set(src_swig_engine_files nupic/bindings/engine_internal.i) @@ -721,16 +762,15 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) SWIG_MODULE_NAME engine_internal) set(src_swig_engine engine_internal) # Make sure we don't attempt to execute the swig executable until it is built. - set(SWIG_MODULE_${src_swig_engine}_EXTRA_DEPS Swig LibStaticNupicCoreCombinedTarget) + set(SWIG_MODULE_${src_swig_engine}_EXTRA_DEPS ${src_swig_extra_deps}) # Create custom command for generating files from SWIG. - swig_add_module(${src_swig_engine} python - ${src_swig_support_files} - ${src_swig_engine_files}) + swig_add_module(${src_swig_engine} python ${src_swig_engine_files}) list(APPEND src_swig_generated_files ${swig_generated_file_fullname}) swig_link_libraries(${src_swig_engine} ${src_swig_link_libraries}) set_target_properties(${SWIG_MODULE_${src_swig_engine}_REAL_NAME} PROPERTIES - LINK_FLAGS "${PYEXT_LINKER_FLAGS_OPTIMIZED}") + LINK_FLAGS "${src_swig_extension_link_flags}") + prepend_boilerplate_to_python_proxy_module(${src_swig_engine}) # Experimental set(src_swig_experimental_files nupic/bindings/experimental.i) @@ -739,16 +779,15 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) SWIG_MODULE_NAME experimental) set(src_swig_experimental experimental) # Make sure we don't attempt to execute the swig executable until it is built. - set(SWIG_MODULE_${src_swig_experimental}_EXTRA_DEPS Swig LibStaticNupicCoreCombinedTarget) + set(SWIG_MODULE_${src_swig_experimental}_EXTRA_DEPS ${src_swig_extra_deps}) # Create custom command for generating files from SWIG. - swig_add_module(${src_swig_experimental} python - ${src_swig_support_files} - ${src_swig_experimental_files}) + swig_add_module(${src_swig_experimental} python ${src_swig_experimental_files}) list(APPEND src_swig_generated_files ${swig_generated_file_fullname}) swig_link_libraries(${src_swig_experimental} ${src_swig_link_libraries}) set_target_properties(${SWIG_MODULE_${src_swig_experimental}_REAL_NAME} PROPERTIES - LINK_FLAGS "${PYEXT_LINKER_FLAGS_OPTIMIZED}") + LINK_FLAGS "${src_swig_extension_link_flags}") + prepend_boilerplate_to_python_proxy_module(${src_swig_experimental}) # Math set(src_swig_math_files nupic/bindings/math.i) @@ -757,27 +796,24 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) SWIG_MODULE_NAME math) set(src_swig_math math) # Make sure we don't attempt to execute the swig executable until it is built. - set(SWIG_MODULE_${src_swig_math}_EXTRA_DEPS Swig LibStaticNupicCoreCombinedTarget) + set(SWIG_MODULE_${src_swig_math}_EXTRA_DEPS ${src_swig_extra_deps}) # Create custom command for generating files from SWIG. - swig_add_module(${src_swig_math} python - ${src_swig_support_files} - ${src_swig_math_files}) + swig_add_module(${src_swig_math} python ${src_swig_math_files}) list(APPEND src_swig_generated_files ${swig_generated_file_fullname}) swig_link_libraries(${src_swig_math} ${src_swig_link_libraries}) set_target_properties(${SWIG_MODULE_${src_swig_math}_REAL_NAME} PROPERTIES - LINK_FLAGS "${PYEXT_LINKER_FLAGS_OPTIMIZED}") + LINK_FLAGS "${src_swig_extension_link_flags}") + prepend_boilerplate_to_python_proxy_module(${src_swig_math}) + + # Set properties on swig-generated and support files set_source_files_properties(${src_swig_generated_files} PROPERTIES GENERATED TRUE) - - set_source_files_properties(${src_swig_generated_files} - PROPERTIES - COMPILE_FLAGS ${swig_generated_file_compile_flags}) - - set_source_files_properties(${src_swig_support_files} - PROPERTIES - COMPILE_FLAGS ${src_compile_flags}) + set_source_files_properties( + ${src_swig_generated_files} + PROPERTIES + COMPILE_FLAGS ${src_swig_generated_file_compile_flags}) # If a path is specified, copy extensions files to proper location. if (PY_EXTENSIONS_DIR) @@ -797,11 +833,12 @@ if (${NUPIC_BUILD_PYEXT_MODULES}) endif() # ${NUPIC_BUILD_PYEXT_MODULES} + # # Install targets into CMAKE_INSTALL_PREFIX # install(TARGETS - ${src_lib_static_nupiccore_solo} + ${src_lib_static_nupiccore_combined} ${src_lib_static_gtest} ${src_executable_helloregion} ${src_executable_cppregiontest} @@ -837,8 +874,6 @@ install(DIRECTORY "${src_numpy_core}/lib/" install(DIRECTORY "${src_numpy_core}/include/" DESTINATION include) -install(FILES ${CAPNP_LINK_LIBRARIES} - DESTINATION lib) foreach(directory ${CAPNP_INCLUDE_DIRS}) install(DIRECTORY "${directory}/capnp" DESTINATION include) @@ -846,9 +881,6 @@ foreach(directory ${CAPNP_INCLUDE_DIRS}) DESTINATION include) endforeach() -install(FILES ${src_lib_static_nupiccore_combined} - DESTINATION lib) - install(DIRECTORY nupic/py_support DESTINATION include/nupic FILES_MATCHING PATTERN "*.c*") install(DIRECTORY nupic DESTINATION include/nupic diff --git a/src/CombineUnixArchives.cmake b/src/CombineUnixArchives.cmake new file mode 100644 index 0000000000..5191faa1a0 --- /dev/null +++ b/src/CombineUnixArchives.cmake @@ -0,0 +1,92 @@ +# ----------------------------------------------------------------------------- +# Numenta Platform for Intelligent Computing (NuPIC) +# Copyright (C) 2016, Numenta, Inc. Unless you have purchased from +# Numenta, Inc. a separate commercial license for this software code, the +# following terms and conditions apply: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero Public License version 3 as +# published by the Free Software Foundation. +# +# This program 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 Affero Public License for more details. +# +# You should have received a copy of the GNU Affero Public License +# along with this program. If not, see http://www.gnu.org/licenses. +# +# http://numenta.org/licenses/ +# ----------------------------------------------------------------------------- + +# Combine multiple Unix static libraries into a single static library. +# +# This script is intended to be invoked via `${CMAKE_COMMAND} -DLIB_TARGET= ...`. +# +# ARGS: +# +# LIB_TARGET: target name of resulting static library (passed to add_library) +# TARGET_LOCATION: Full path to the target library +# SRC_LIB_LOCATIONS: List of source static library paths +# LIST_SEPARATOR: separator string that separates paths in +# SRC_LIB_LOCATIONS; NOTE with cmake 2.8.11+, caller could use the generator +# "$" in SRC_LIB_LOCATIONS, and this arg would be unnecessary. +# BINARY_DIR: The value of ${CMAKE_CURRENT_BINARY_DIR} from caller +# CMAKE_AR: The value of ${CMAKE_AR} from caller + +function(COMBINE_UNIX_ARCHIVES + LIB_TARGET + TARGET_LOCATION + SRC_LIB_LOCATIONS + LIST_SEPARATOR + BINARY_DIR + CMAKE_AR) + + message(STATUS + "COMBINE_UNIX_ARCHIVES(" + " LIB_TARGET=${LIB_TARGET}, " + " TARGET_LOCATION=${TARGET_LOCATION}, " + " SRC_LIB_LOCATIONS=${SRC_LIB_LOCATIONS}, " + " LIST_SEPARATOR=${LIST_SEPARATOR}, " + " BINARY_DIR=${BINARY_DIR}, " + " CMAKE_AR=${CMAKE_AR})") + + string(REPLACE ${LIST_SEPARATOR} ";" + SRC_LIB_LOCATIONS "${SRC_LIB_LOCATIONS}") + + set(scratch_dir ${BINARY_DIR}/combine_unix_archives_${LIB_TARGET}) + file(MAKE_DIRECTORY ${scratch_dir}) + + # Extract archives into individual directories to avoid object file collisions + set(all_object_locations) + foreach(lib ${SRC_LIB_LOCATIONS}) + message(STATUS "COMBINE_UNIX_ARCHIVES: LIB_TARGET=${LIB_TARGET}, src-lib=${lib}") + # Create working directory for current source lib + get_filename_component(basename ${lib} NAME) + set(working_dir ${scratch_dir}/${basename}.dir) + file(MAKE_DIRECTORY ${working_dir}) + + # Extract objects from current source lib + execute_process(COMMAND ${CMAKE_AR} -x ${lib} + WORKING_DIRECTORY ${working_dir}) + + # Accumulate objects + file(GLOB_RECURSE objects "${working_dir}/*") + list(APPEND all_object_locations ${objects}) + endforeach() + + # Generate the target static library from all source objects + file(TO_NATIVE_PATH ${TARGET_LOCATION} TARGET_LOCATION) + execute_process(COMMAND ${CMAKE_AR} rcs ${TARGET_LOCATION} ${all_object_locations}) + + # Remove scratch directory + file(REMOVE_RECURSE ${scratch_dir}) +endfunction(COMBINE_UNIX_ARCHIVES) + + +combine_unix_archives(${LIB_TARGET} + ${TARGET_LOCATION} + "${SRC_LIB_LOCATIONS}" + ${LIST_SEPARATOR} + ${BINARY_DIR} + ${CMAKE_AR}) diff --git a/src/ConcatTwoFiles.cmake b/src/ConcatTwoFiles.cmake new file mode 100644 index 0000000000..5eaa035610 --- /dev/null +++ b/src/ConcatTwoFiles.cmake @@ -0,0 +1,40 @@ +# ----------------------------------------------------------------------------- +# Numenta Platform for Intelligent Computing (NuPIC) +# Copyright (C) 2016, Numenta, Inc. Unless you have purchased from +# Numenta, Inc. a separate commercial license for this software code, the +# following terms and conditions apply: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero Public License version 3 as +# published by the Free Software Foundation. +# +# This program 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 Affero Public License for more details. +# +# You should have received a copy of the GNU Affero Public License +# along with this program. If not, see http://www.gnu.org/licenses. +# +# http://numenta.org/licenses/ +# ----------------------------------------------------------------------------- + +# Concatenates two files into a target file, overwriting target file if already +# exists; either of the source files may be the same path as the target file. + +# This script is intended to be invoked via `${CMAKE_COMMAND} -DSRC_FILE_1= ...`. + +# ARGS: +# +# SRC_FILE_1: path of first source file; may be same as TARGET_FILE. +# SRC_FILE_2: path of second source file; may be same as TARGET_FILE. +# TARGET_FILE: path of target file. + + +function(CONCAT_TWO_FILES SRC_FILE_1 SRC_FILE_2 TARGET_FILE) + file(READ ${SRC_FILE_1} src_1_content) + file(READ ${SRC_FILE_2} src_2_content) + file(WRITE ${TARGET_FILE} "${src_1_content}${src_2_content}") +endfunction(CONCAT_TWO_FILES) + +concat_two_files(${SRC_FILE_1} ${SRC_FILE_2} ${TARGET_FILE}) diff --git a/src/NupicLibraryUtils.cmake b/src/NupicLibraryUtils.cmake new file mode 100644 index 0000000000..c997483fd4 --- /dev/null +++ b/src/NupicLibraryUtils.cmake @@ -0,0 +1,140 @@ +# ----------------------------------------------------------------------------- +# Numenta Platform for Intelligent Computing (NuPIC) +# Copyright (C) 2016, Numenta, Inc. Unless you have purchased from +# Numenta, Inc. a separate commercial license for this software code, the +# following terms and conditions apply: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero Public License version 3 as +# published by the Free Software Foundation. +# +# This program 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 Affero Public License for more details. +# +# You should have received a copy of the GNU Affero Public License +# along with this program. If not, see http://www.gnu.org/licenses. +# +# http://numenta.org/licenses/ +# ----------------------------------------------------------------------------- + +# Utilities for manipulating libraries + +cmake_minimum_required(VERSION 2.8) +project(nupic_core_library_utils CXX) + + +# function MERGE_STATIC_LIBRARIES +# +# Generate a new static library target that will merge the objects +# of the given static libraries. +# +# :param LIB_TARGET: the name to use for the new library target to be +# passed verbatim as the target arg to `ADD_LIBRARY` +# +# :param STATIC_LIBS: a list of static libraries to be merge. The +# elements of this list may be a combination of archive file paths and +# static library target names (i.e., those defined here via +# add_library(xyz STATIC ...)). + +function(MERGE_STATIC_LIBRARIES LIB_TARGET STATIC_LIBS) + + message(STATUS "MERGE_STATIC_LIBRARIES " + "LIB_TARGET=${LIB_TARGET}, " + "STATIC_LIBS = ${STATIC_LIBS}") + + # We need at least one source file for ADD_LIBRARY + set(dummy_source_file "${CMAKE_CURRENT_BINARY_DIR}/${LIB_TARGET}_dummy.c++") + + # Define a static lib containing the dummy source file; we will subsequently + # add a post-build custom step that will add the objects from the given static + # libraries + add_library(${LIB_TARGET} STATIC ${dummy_source_file}) + set_target_properties(${LIB_TARGET} PROPERTIES COMPILE_FLAGS + ${INTERNAL_CXX_FLAGS_OPTIMIZED}) + + set(static_lib_locations) + set(dummy_dependencies) + set(link_libs) + + foreach(lib ${STATIC_LIBS}) + list(APPEND dummy_dependencies ${lib}) + + if (NOT TARGET ${lib}) + # Assuming a path of an externally-generated static library + list(APPEND static_lib_locations ${lib}) + else() + # Assuming a cmake static library target + get_target_property(lib_type ${lib} TYPE) + if(NOT ${lib_type} STREQUAL "STATIC_LIBRARY") + message(FATAL_ERROR "Expected static lib source object ${lib}, but got type=${lib_type}!") + endif() + + list(APPEND static_lib_locations "$") + add_dependencies(${LIB_TARGET} ${lib}) + + # Collect its link interface + get_target_property(link_iface ${lib} INTERFACE_LINK_LIBRARIES) + if (link_iface) + list(APPEND link_libs ${link_iface}) + message(STATUS "MERGE_STATIC_LIBRARIES: " + "INTERFACE_LINK_LIBRARIES[${lib}] = ${link_iface}.") + else() + message(STATUS "MERGE_STATIC_LIBRARIES: " + "Link interface not specified in source lib ${lib}.") + endif() + endif() + endforeach() + + # Transfer link interface of source libraries to target + if (link_libs) + list(REMOVE_DUPLICATES link_libs) + target_link_libraries(${LIB_TARGET} ${link_libs}) + endif() + + # Force relink whenever any of the source libraries change + add_custom_command(OUTPUT ${dummy_source_file} + COMMAND ${CMAKE_COMMAND} -E touch ${dummy_source_file} + DEPENDS ${dummy_dependencies}) + + # Merge the archives + if(MSVC) + # pass source libs to lib.exe via STATIC_LIBRARY_FLAGS target property + + set(msvc_library_flags "") + foreach(lib_location ${static_lib_locations}) + set(msvc_library_flags "${msvc_library_flags} ${lib_location}") + endforeach() + set_target_properties(${LIB_TARGET} PROPERTIES STATIC_LIBRARY_FLAGS + "${msvc_library_flags}") + else() + # UNIX OR MSYS OR MINGW: use post-build command to extract objects from + # source libs and repack them for the target library + + set(target_location_gen "$") + + # NOTE With cmake 2.8.11+, we could use "$", but default Travis + # environment is configured with cmake 2.8.7 + set(lib_locations_separator "++++") + string(REPLACE ";" ${lib_locations_separator} + escaped_lib_locations_arg "${static_lib_locations}") + + add_custom_command( + TARGET ${LIB_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove "${target_location_gen}" + COMMAND + ${CMAKE_COMMAND} + -DLIB_TARGET="${LIB_TARGET}" + -DTARGET_LOCATION="${target_location_gen}" + -DSRC_LIB_LOCATIONS="${escaped_lib_locations_arg}" + -DLIST_SEPARATOR=${lib_locations_separator} + -DBINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" + -DCMAKE_AR="${CMAKE_AR}" + -P ${CMAKE_SOURCE_DIR}/src/CombineUnixArchives.cmake + COMMENT "Combining ${target_location_gen} for target ${LIB_TARGET} from ${static_lib_locations}." + ) + + endif() + +endfunction(MERGE_STATIC_LIBRARIES) diff --git a/src/nupic/bindings/algorithms.i b/src/nupic/bindings/algorithms.i index be3fdb883a..66adda8c79 100644 --- a/src/nupic/bindings/algorithms.i +++ b/src/nupic/bindings/algorithms.i @@ -25,31 +25,9 @@ %import %pythoncode %{ -# ---------------------------------------------------------------------- -# Numenta Platform for Intelligent Computing (NuPIC) -# Copyright (C) 2013-2015, Numenta, Inc. Unless you have an agreement -# with Numenta, Inc., for a separate license for this software code, the -# following terms and conditions apply: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero Public License version 3 as -# published by the Free Software Foundation. -# -# This program 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 Affero Public License for more details. -# -# You should have received a copy of the GNU Affero Public License -# along with this program. If not, see http://www.gnu.org/licenses. -# -# http://numenta.org/licenses/ -# ---------------------------------------------------------------------- - import os _ALGORITHMS = _algorithms - %} %{ @@ -142,6 +120,7 @@ using namespace nupic; %} + // %pythoncode %{ // import numpy // from bindings import math diff --git a/src/nupic/bindings/engine_internal.i b/src/nupic/bindings/engine_internal.i index 186b3a47fb..c1543435a0 100644 --- a/src/nupic/bindings/engine_internal.i +++ b/src/nupic/bindings/engine_internal.i @@ -23,30 +23,6 @@ %module(package="bindings") engine_internal %include -%pythoncode %{ -# ---------------------------------------------------------------------- -# Numenta Platform for Intelligent Computing (NuPIC) -# Copyright (C) 2013, Numenta, Inc. Unless you have an agreement -# with Numenta, Inc., for a separate license for this software code, the -# following terms and conditions apply: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero Public License version 3 as -# published by the Free Software Foundation. -# -# This program 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 Affero Public License for more details. -# -# You should have received a copy of the GNU Affero Public License -# along with this program. If not, see http://www.gnu.org/licenses. -# -# http://numenta.org/licenses/ -# ---------------------------------------------------------------------- - -%} - %{ /* --------------------------------------------------------------------- * Numenta Platform for Intelligent Computing (NuPIC) @@ -106,6 +82,7 @@ #include %} + %include "std_pair.i" %include "std_string.i" %include "std_vector.i" diff --git a/src/nupic/bindings/experimental.i b/src/nupic/bindings/experimental.i index d16e90f688..4f42a6e2bb 100644 --- a/src/nupic/bindings/experimental.i +++ b/src/nupic/bindings/experimental.i @@ -24,31 +24,9 @@ %import %pythoncode %{ -# ---------------------------------------------------------------------- -# Numenta Platform for Intelligent Computing (NuPIC) -# Copyright (C) 2013-2016, Numenta, Inc. Unless you have an agreement -# with Numenta, Inc., for a separate license for this software code, the -# following terms and conditions apply: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero Public License version 3 as -# published by the Free Software Foundation. -# -# This program 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 Affero Public License for more details. -# -# You should have received a copy of the GNU Affero Public License -# along with this program. If not, see http://www.gnu.org/licenses. -# -# http://numenta.org/licenses/ -# ---------------------------------------------------------------------- - import os _EXPERIMENTAL = _experimental - %} %{ diff --git a/src/nupic/bindings/math.i b/src/nupic/bindings/math.i index d027186150..c1d4228ceb 100644 --- a/src/nupic/bindings/math.i +++ b/src/nupic/bindings/math.i @@ -24,29 +24,7 @@ %include %pythoncode %{ -# ---------------------------------------------------------------------- -# Numenta Platform for Intelligent Computing (NuPIC) -# Copyright (C) 2013, Numenta, Inc. Unless you have an agreement -# with Numenta, Inc., for a separate license for this software code, the -# following terms and conditions apply: -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero Public License version 3 as -# published by the Free Software Foundation. -# -# This program 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 Affero Public License for more details. -# -# You should have received a copy of the GNU Affero Public License -# along with this program. If not, see http://www.gnu.org/licenses. -# -# http://numenta.org/licenses/ -# ---------------------------------------------------------------------- - _MATH = _math - %} %{ @@ -100,7 +78,7 @@ _MATH = _math // Perform necessary library initialization (in C++). import_array(); - + %} %include @@ -171,7 +149,7 @@ import_array(); x_min, x_max, 1, 65535); return y.forPython(); } - */ + */ PyObject* winnerTakesAll_3(size_t k, size_t seg_size, PyObject* py_x) { diff --git a/src/nupic/bindings/sparse_matrix.i b/src/nupic/bindings/sparse_matrix.i index 9104a90f22..cce981974e 100644 --- a/src/nupic/bindings/sparse_matrix.i +++ b/src/nupic/bindings/sparse_matrix.i @@ -33,12 +33,13 @@ #include #include -%} +%} + //-------------------------------------------------------------------------------- // Global epsilon //-------------------------------------------------------------------------------- -%inline { +%inline { nupic::Real getGlobalEpsilon() { return nupic::Epsilon; } @@ -82,11 +83,11 @@ allowed_scalar_types = ['int', 'float', 'float32', 'float64', 'float128'] -def __init__(self, *args): +def __init__(self, *args): """ Constructs a new SparseMatrix from the following available arguments: SparseMatrix(): An empty sparse matrix with 0 rows and columns. - SparseMatrix(nrows, ncols): A zero sparse matrix with the + SparseMatrix(nrows, ncols): A zero sparse matrix with the specified rows and columns. SparseMatrix(SparseMatrix): Copies an existing sparse matrix. SparseMatrix(string): Loads a SparseMatrix from its serialized form. @@ -95,49 +96,49 @@ def __init__(self, *args): """ serialized,dense,from01,fromstr3f = None,None,False,False fromSpecRowCols = False - + if (len(args) == 3) and isinstance(args[0], _SparseMatrix32): fromSpecRowCols = True if (len(args) == 1): if isinstance(args[0], basestring): serialized = args[0] - args = tuple() + args = tuple() elif isinstance(args[0], numpy.ndarray): - dense = args[0] - args = tuple() + dense = args[0] + args = tuple() elif hasattr(args[0], '__iter__'): - dense = args[0] - args = tuple() + dense = args[0] + args = tuple() elif isinstance(args[0], _SM_01_32_32): #or isinstance(args[0], _SM_01_32_16): from01 = True - if from01 or fromSpecRowCols: + if from01 or fromSpecRowCols: this = _MATH.new__SparseMatrix ## N2(1,1) else: this = _MATH.new__SparseMatrix ## N2(*args) - - try: + + try: self.this.append(this) - except: + except: self.this = this - if serialized is not None: + if serialized is not None: s = serialized.split(None, 1) - self.fromPyString(serialized) - + self.fromPyString(serialized) + elif dense is not None: - self.fromDense(numpy.asarray(dense,dtype=GetNumpyDataType('NTA_Real' + #N2))) - + self.fromDense(numpy.asarray(dense,dtype=GetNumpyDataType('NTA_Real' + #N2))) + elif from01: nz_i,nz_j = args[0].getAllNonZeros(True) nz_ones = numpy.ones((len(nz_i))) - self.setAllNonZeros(args[0].nRows(), args[0].nCols(), nz_i, nz_j, nz_ones) - + self.setAllNonZeros(args[0].nRows(), args[0].nCols(), nz_i, nz_j, nz_ones) + elif fromstr3f: nz_i,nz_j,nz_v = args[1].getAllNonZeros(args[0], True) - self.setAllNonZeros(args[1].nRows(), args[1].nCols(), nz_i,nz_j,nz_v) - + self.setAllNonZeros(args[1].nRows(), args[1].nCols(), nz_i,nz_j,nz_v) + elif fromSpecRowCols: if args[2] == 0: self.__initializeWithRows(args[0], args[1]) @@ -168,7 +169,7 @@ def __init__(self, *args): # slices[cur] = slice(0, bounds[cur], 1) # cur += 1 # slices[cur] = slice(0, bounds[cur], 1) -# elif isinstance(dim, slice): +# elif isinstance(dim, slice): # slices[cur] = self._fixSlice(dim, bounds[cur]) # else: slices[cur] = slice(dim, dim, 0) # cur += 1 @@ -177,7 +178,7 @@ def __init__(self, *args): # def getSliceWrap(self, key): # bounds = [ self.nRows(), self.nCols() ] d = self._getDomain(key, bounds) # return self.getSlice(d[0].getLB(), d[0].getUB(), d[1].getLB(), d[1].getUB()) - + # def setSliceWrap(self, key, value): # bounds = [ self.nRows(), self.nCols() ] d = self._getDomain(key, bounds) # return self.setSlice(d[0].getLB(), d[1].getLB(), value) @@ -295,7 +296,7 @@ def __isub__(self, other): elif t == 'ndarray': self.subtract(_SparseMatrix ## N2(other)) elif t == '_SparseMatrix' + #N2: - self.subtract(other) + self.subtract(other) else: raise Exception("Can't use type: " + t) return self @@ -308,7 +309,7 @@ def __sub__(self, other): elif t == 'ndarray': result.subtract(_SparseMatrix ## N2(other)) elif t == '_SparseMatrix' + #N2: - result.subtract(other) + result.subtract(other) else: raise Exception("Can't use type: " + t) return result @@ -321,7 +322,7 @@ def __imul__(self, other): if t in self.allowed_scalar_types: self.__multiply(other) elif t == '_SparseMatrix' + #N2: - self.multiply(other) + self.multiply(other) else: raise Exception("Can't use type: " + t) return self @@ -400,29 +401,29 @@ def __div__(self, other): t = type(other).__name__ if t in self.allowed_scalar_types: result = _SparseMatrix ## N2(self) - result.__divide(other) + result.__divide(other) return result else: raise Exception("Can't use type: " + t) %} - + void __initializeWithRows(const SparseMatrix ##N2& other, PyObject* py_take) { nupic::NumpyVectorT take(py_take); self->initializeWithRows(other, take.begin(), take.end()); } - + void __initializeWithCols(const SparseMatrix ##N2& other, PyObject* py_take) { nupic::NumpyVectorT take(py_take); self->initializeWithCols(other, take.begin(), take.end()); } - void __add(PyObject* val) + void __add(PyObject* val) { self->add(nupic::convertToValueType(val)); } - + void __multiply(PyObject* val) { self->multiply(nupic::convertToValueType(val)); @@ -432,7 +433,7 @@ def __div__(self, other): { self->subtract(nupic::convertToValueType(val)); } - + void __divide(PyObject* val) { self->divide(nupic::convertToValueType(val)); @@ -449,7 +450,7 @@ def __div__(self, other): self->fromDense(m.rows(), m.columns(), m.addressOf(0, 0)); } - PyObject *toDense() const + PyObject *toDense() const { int dims[] = { static_cast(self->nRows()), static_cast(self->nCols()) }; nupic::NumpyMatrixT out(dims); @@ -458,7 +459,7 @@ def __div__(self, other): } void _setRowFromDense(nupic::UInt ## N1 row, PyObject* py_row) - { + { nupic::NumpyVectorT row_data(py_row); self->setRowFromDense(row, row_data.begin()); } @@ -534,13 +535,13 @@ def __div__(self, other): nupic::NumpyVectorT cpp_nz(nz); self->addCol(cpp_ind.begin(), cpp_ind.end(), cpp_nz.begin()); } - + void deleteRows(PyObject *rowIndices) { nupic::NumpyVectorT cpp_rowIndices(rowIndices); self->deleteRows(cpp_rowIndices.begin(), cpp_rowIndices.end()); } - + void deleteCols(PyObject *colIndices) { nupic::NumpyVectorT cpp_colIndices(colIndices); @@ -811,11 +812,11 @@ def __div__(self, other): self->incrementOnOuterWNZ(i.begin(), i.end(), j.begin(), j.end(), delta); } - void incrementOnOuterWNZWThreshold(PyObject* py_i, PyObject* py_j, + void incrementOnOuterWNZWThreshold(PyObject* py_i, PyObject* py_j, nupic::Real ## N2 threshold, nupic::Real ## N2 delta=1) { nupic::NumpyVectorT i(py_i), j(py_j); - self->incrementOnOuterWNZWThreshold(i.begin(), i.end(), j.begin(), j.end(), + self->incrementOnOuterWNZWThreshold(i.begin(), i.end(), j.begin(), j.end(), threshold, delta); } @@ -856,7 +857,7 @@ def __div__(self, other): nupic::NumpyVectorT bounds_j(box_j); SparseMatrix ## N1 result(bounds_i.size(), bounds_j.size()); self->nNonZerosPerBox(bounds_i.begin(), bounds_i.end(), - bounds_j.begin(), bounds_j.end(), + bounds_j.begin(), bounds_j.end(), result); return result; } @@ -884,7 +885,7 @@ def __div__(self, other): self->rowMin(row_index, idx, min_val); return nupic::createPair ## N1(idx, min_val); } - + PyObject* rowMax(nupic::UInt ## N1 row_index) const { nupic::UInt ## N1 idx; @@ -892,7 +893,7 @@ def __div__(self, other): self->rowMax(row_index, idx, max_val); return nupic::createPair ## N1(idx, max_val); } - + PyObject* colMin(nupic::UInt ## N1 col_index) const { nupic::UInt ## N1 idx; @@ -900,7 +901,7 @@ def __div__(self, other): self->colMin(col_index, idx, min_val); return nupic::createPair ## N1(idx, min_val); } - + PyObject* colMax(nupic::UInt ## N1 row_index) const { nupic::UInt ## N1 idx; @@ -980,10 +981,10 @@ def __div__(self, other): const nupic::Real ## N2& value) const { std::vector rows, cols; - self->whereEqual(begin_row, end_row, begin_col, end_col, value, + self->whereEqual(begin_row, end_row, begin_col, end_col, value, std::back_inserter(rows), std::back_inserter(cols)); - PyObject* toReturn = PyTuple_New(rows.size()); + PyObject* toReturn = PyTuple_New(rows.size()); for (size_t i = 0; i != rows.size(); ++i) { PyObject* p = PyTuple_New(2); @@ -1000,19 +1001,19 @@ def __div__(self, other): const nupic::Real ## N2& value) const { std::vector rows, cols; - self->whereGreater(begin_row, end_row, begin_col, end_col, value, + self->whereGreater(begin_row, end_row, begin_col, end_col, value, std::back_inserter(rows), std::back_inserter(cols)); int dims[] = {static_cast(rows.size()), 2}; nupic::NumpyMatrixT toReturn(dims); - for (size_t i = 0; i != rows.size(); ++i) { + for (size_t i = 0; i != rows.size(); ++i) { toReturn.set(i, 0, rows[i]); toReturn.set(i, 1, cols[i]); } return toReturn.forPython(); /* - PyObject* toReturn = PyTuple_New(rows.size()); + PyObject* toReturn = PyTuple_New(rows.size()); for (size_t i = 0; i != rows.size(); ++i) { PyObject* p = PyTuple_New(2); PyTuple_SET_ITEM(p, 0, PyInt_FromLong(rows[i])); @@ -1029,20 +1030,20 @@ def __div__(self, other): const nupic::Real ## N2& value) const { std::vector rows, cols; - self->whereGreaterEqual(begin_row, end_row, begin_col, end_col, value, + self->whereGreaterEqual(begin_row, end_row, begin_col, end_col, value, std::back_inserter(rows), std::back_inserter(cols)); - - + + int dims[] = {static_cast(rows.size()), 2}; nupic::NumpyMatrixT toReturn(dims); - for (size_t i = 0; i != rows.size(); ++i) { + for (size_t i = 0; i != rows.size(); ++i) { toReturn.set(i, 0, rows[i]); toReturn.set(i, 1, cols[i]); } return toReturn.forPython(); /* - PyObject* toReturn = PyTuple_New(rows.size()); + PyObject* toReturn = PyTuple_New(rows.size()); for (size_t i = 0; i != rows.size(); ++i) { PyObject* p = PyTuple_New(2); @@ -1089,7 +1090,7 @@ def __div__(self, other): return m.forPython(); } - PyObject* addRows(PyObject* whichRows) const + PyObject* addRows(PyObject* whichRows) const { nupic::NumpyVectorT indicator(whichRows); nupic::NumpyVectorT res(self->nCols()); @@ -1097,7 +1098,7 @@ def __div__(self, other): return res.forPython(); } - PyObject* addListOfRows(PyObject* py_whichRows) const + PyObject* addListOfRows(PyObject* py_whichRows) const { nupic::NumpyVectorT whichRows(py_whichRows); nupic::NumpyVectorT res(self->nCols()); @@ -1145,14 +1146,14 @@ def __div__(self, other): self->scaleCols(s.begin()); } - void normalizeBlockByRows(PyObject* py_inds, + void normalizeBlockByRows(PyObject* py_inds, nupic::Real ## N2 val=-1.0, nupic::Real ## N2 eps_n=1e-6) { nupic::NumpyVectorT inds(py_inds); self->normalizeBlockByRows(inds.begin(), inds.end(), val, eps_n); } - void normalizeBlockByRows_binary(PyObject* py_inds, + void normalizeBlockByRows_binary(PyObject* py_inds, nupic::Real ## N2 val=-1.0, nupic::Real ## N2 eps_n=1e-6) { nupic::NumpyVectorT inds(py_inds); @@ -1211,7 +1212,7 @@ def __div__(self, other): return y.forPython(); } - SparseMatrix ## N2 + SparseMatrix ## N2 blockRightVecProd(nupic::UInt ## N1 block_size, PyObject* xIn) const { SparseMatrix ## N2 result; @@ -1220,14 +1221,14 @@ def __div__(self, other): return result; } - // Dot product of column col and vector xIn. + // Dot product of column col and vector xIn. nupic::Real ## N2 leftVecProd(nupic::UInt ## N1 col, PyObject *xIn) const { nupic::NumpyVectorT x(xIn); return self->leftVecProd(col, x.begin()); } - // Vector matrix product on the left, i.e. dot product of xIn and + // Vector matrix product on the left, i.e. dot product of xIn and // each column of the matrix. PyObject* leftVecProd(PyObject *xIn) const { @@ -1373,7 +1374,7 @@ def __div__(self, other): // Regular matrix vector multiplication, but assumes that all the non-zeros // in the SparseMatrix are 1, so that we can save computing the multiplications: // this routine just adds the values of xIn at the positions of the non-zeros - // on each row. + // on each row. inline PyObject* rightVecSumAtNZ(PyObject* xIn) const { nupic::NumpyVectorT x(xIn); @@ -1381,8 +1382,8 @@ def __div__(self, other): self->rightVecSumAtNZ(x.begin(), y.begin()); return y.forPython(); } - - inline PyObject* + + inline PyObject* rightVecSumAtNZGtThreshold(PyObject* xIn, nupic::Real ## 32 threshold) const { nupic::NumpyVectorT x(xIn); @@ -1392,7 +1393,7 @@ def __div__(self, other): } // Regular matrix vector multiplication, without allocation of the result, - // and assuming that the values of the non-zeros are always 1 in the + // and assuming that the values of the non-zeros are always 1 in the // sparse matrix, so that we can save computing multiplications explicitly. // Also fast because doesn't go through NumpyVectorT and doesn't allocate // memory. @@ -1405,7 +1406,7 @@ def __div__(self, other): self->rightVecSumAtNZ(x_begin, y_begin); } - // Regular matrix vector multiplication on the left side, assuming that the + // Regular matrix vector multiplication on the left side, assuming that the // values of the non-zeros are all 1, so that we can save actually computing // the multiplications. Allocates the result. inline PyObject* leftVecSumAtNZ(PyObject* xIn) const @@ -1416,8 +1417,8 @@ def __div__(self, other): return y.forPython(); } - // Regular matrix vector multiplication on the left, without allocation - // of the result, assuming that the values of the non-zeros are always 1 in the + // Regular matrix vector multiplication on the left, without allocation + // of the result, assuming that the values of the non-zeros are always 1 in the // sparse matrix, so that we can save computing multiplications explicitly. // Also fast because doesn't go through NumpyVectorT and doesn't allocate // memory. @@ -1562,7 +1563,7 @@ def __div__(self, other): self->getNonZerosSorted(ijvs.begin(), N, IJV::less_value()); PyObject* toReturn = PyTuple_New(N); for (nupic::UInt ## N1 i = 0; i != N; ++i) { - PyObject* tuple = + PyObject* tuple = nupic::createTriplet ## N1(ijvs[i].i(), ijvs[i].j(), ijvs[i].v()); PyTuple_SET_ITEM(toReturn, i, tuple); } @@ -1575,12 +1576,12 @@ def __div__(self, other): if (!getCuts) { self->threshold(threshold); return NULL; - } + } std::vector cut_i, cut_j; std::vector cut_nz; nupic::UInt ## N1 c = 0; - c = self->threshold(threshold, + c = self->threshold(threshold, std::back_inserter(cut_i), std::back_inserter(cut_j), std::back_inserter(cut_nz)); @@ -1601,7 +1602,7 @@ def __div__(self, other): return py_s.close(); } - bool fromPyString(PyObject *s) + bool fromPyString(PyObject *s) { Py_ssize_t n = 0; char *buf = 0; @@ -1622,7 +1623,7 @@ def __div__(self, other): bool __ne__(const SparseMatrix ## N2& other) const { return (*self) != other; } -} // End extend SparseMatrix +} // End extend SparseMatrix %enddef // End def macro SparseMatrix_ //-------------------------------------------------------------------------------- @@ -1670,7 +1671,7 @@ void aX_plus_bX_elementMultiply_Y( } */ -PyObject* +PyObject* kthroot_product(const nupic::SparseMatrix > & sm, nupic::UInt32 segment_size, PyObject* xIn, nupic::Real32 threshold) { nupic::NumpyVectorT x(xIn), y(sm.nRows()); @@ -1679,7 +1680,7 @@ kthroot_product(const nupic::SparseMatrix > & sm, nupic::UInt32 segment_size, PyObject* xIn, nupic::Real64 threshold) { nupic::NumpyVectorT x(xIn), y(sm.nRows()); @@ -1749,7 +1750,7 @@ inline PyObject* binarize_with_threshold(nupic::Real32 threshold, PyObject* py_x //-------------------------------------------------------------------------------- // Functions on 2D dense arrays of 0/1 //-------------------------------------------------------------------------------- -inline PyObject* +inline PyObject* nonZeroRowsIndicator_01(nupic::UInt32 nrows, nupic::UInt32 ncols, PyObject* py_x) { PyArrayObject* x = (PyArrayObject*) py_x; @@ -1760,7 +1761,7 @@ nonZeroRowsIndicator_01(nupic::UInt32 nrows, nupic::UInt32 ncols, PyObject* py_x return ind.forPython(); } -inline PyObject* +inline PyObject* nonZeroColsIndicator_01(nupic::UInt32 nrows, nupic::UInt32 ncols, PyObject* py_x) { PyArrayObject* x = (PyArrayObject*) py_x; @@ -1839,7 +1840,7 @@ inline nupic::UInt32 nNonZeroCols_01(nupic::UInt32 nrows, nupic::UInt32 ncols, P nupic::SparseMatrixAlgorithms::smoothVecArgMaxProd(sm, k, x.begin(), x.end(), y.begin(), y.end()); return y.forPython(); } - + //-------------------------------------------------------------------------------- // LBP //-------------------------------------------------------------------------------- @@ -1908,7 +1909,7 @@ inline nupic::UInt32 nNonZeroCols_01(nupic::UInt32 nrows, nupic::UInt32 ncols, P { nupic::SparseMatrixAlgorithms::addConstantOnNonZeros(A, B, cval); } - + //-------------------------------------------------------------------------------- /* void SM_addConstantOnNonZeros(nupic::SparseMatrix >& A, @@ -1948,7 +1949,7 @@ inline nupic::UInt32 nNonZeroCols_01(nupic::UInt32 nrows, nupic::UInt32 ncols, P nupic::SparseMatrixAlgorithms::logAddValNoAlloc(A, val, min_floor); } */ - + //-------------------------------------------------------------------------------- void SM_logDiffNoAlloc(nupic::SparseMatrix >& A, nupic::SparseMatrix >& B, double min_floor =0) @@ -2017,14 +2018,14 @@ inline nupic::UInt32 nNonZeroCols_01(nupic::UInt32 nrows, nupic::UInt32 ncols, P def SM_assignNoAlloc(sm, right): if hasattr(right, 'logicalAnd'): - # This does doesnt look right. Since we are in the bindings module, + # This does doesnt look right. Since we are in the bindings module, # I think we can just call SM_assignNoAllocFromBinary directly - wcs nupic.bindings.math.SM_assignNoAllocFromBinary(sm, right) else: # Not updating for NuPIC2 because it looks like it leads to an infinite loop - wcs nupic.bindings.math.SM_assignNoAlloc(sm, right) - + %} */ @@ -2064,7 +2065,7 @@ def SM_assignNoAlloc(sm, right): // END LBP //-------------------------------------------------------------------------------- -%inline +%inline { //-------------------------------------------------------------------------------- // Count the number of elements greater than the passed in threshold in the given @@ -2080,7 +2081,7 @@ def SM_assignNoAlloc(sm, right): } //-------------------------------------------------------------------------------- - // Count the number of elements greater than or equal to the passed in + // Count the number of elements greater than or equal to the passed in // threshold in the given range. //-------------------------------------------------------------------------------- inline nupic::UInt32 count_gte(PyObject* py_x, nupic::Real32 threshold) @@ -2106,7 +2107,7 @@ def SM_assignNoAlloc(sm, right): } //-------------------------------------------------------------------------------- - // A partial argsort that can use an already allocated buffer to avoid creating + // A partial argsort that can use an already allocated buffer to avoid creating // a data structure each time it's called. Assumes that the elements to be sorted // are nupic::Real32, or at least that they have the same size. // @@ -2116,11 +2117,11 @@ def SM_assignNoAlloc(sm, right): // If direction is 1, the sort is in increasing order. // // The result is returned in the first k positions of the buffer for speed. - // + // // Uses a pre-allocated buffer to avoid allocating memory each time a sort // is needed. //-------------------------------------------------------------------------------- - inline void + inline void partialArgsort(size_t k, PyObject* py_x, PyObject* py_r, int direction =-1) { PyArrayObject* x = (PyArrayObject*) py_x; @@ -2136,12 +2137,12 @@ def SM_assignNoAlloc(sm, right): //-------------------------------------------------------------------------------- /** - * Specialized partial argsort with selective random tie breaking, only for the + * Specialized partial argsort with selective random tie breaking, only for the * non-zeros of the original coincidence (passed in which). * See partial_argsort_sel_rnd_tie_break for more details. */ - inline void - positiveLearningPartialArgsort(size_t k, + inline void + positiveLearningPartialArgsort(size_t k, PyObject* py_x, PyObject* py_r, nupic::Random& rng, bool real_random =false) @@ -2155,8 +2156,8 @@ def SM_assignNoAlloc(sm, right): nupic::UInt32* r_end = r_begin + PyArray_DIMS(r)[0]; nupic::partial_argsort_rnd_tie_break(k, - x_begin, x_end, - r_begin, r_end, + x_begin, x_end, + r_begin, r_end, rng, real_random); } @@ -2244,7 +2245,7 @@ def SM_assignNoAlloc(sm, right): if dtype == 'Float32': return _SparseMatrix32(*args) #elif dtype == 'Float64': - # return _SparseMatrix64(*args) + # return _SparseMatrix64(*args) #elif dtype == 'Float128': # return _SparseMatrix128(*args) else: @@ -2290,11 +2291,11 @@ def SM_assignNoAlloc(sm, right): { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): """ Constructs a new NearestNeighbor from the following available arguments: NearestNeighbor(): An empty sparse matrix with 0 rows and columns. - NearestNeighbor(nrows, ncols): A zero sparse matrix with the + NearestNeighbor(nrows, ncols): A zero sparse matrix with the specified rows and columns. NearestNeighbor(NearestNeighbor): Copies an existing sparse matrix. NearestNeighbor(string): Loads a NearestNeighbor from its serialized form. @@ -2307,23 +2308,23 @@ def __init__(self, *args): if (len(args) == 1): if isinstance(args[0], basestring): serialized = args[0] - args = tuple() + args = tuple() elif isinstance(args[0], numpy.ndarray): - dense = args[0] - args = tuple() + dense = args[0] + args = tuple() elif isinstance(args[0], _SparseMatrix ## N2): toCopy = args[0] args = tuple() elif hasattr(args[0], '__iter__'): - dense = args[0] - args = tuple() + dense = args[0] + args = tuple() this = _MATH.new__NearestNeighbor ## N2(*args) - try: + try: self.this.append(this) - except: + except: self.this = this if toCopy is not None: self.copy(toCopy) - elif serialized is not None: + elif serialized is not None: s = serialized.split(None, 1) if s[0] != 'csr' and s[0] != 'sm_csr_1.5': raise "Wrong CSR format, should start with 'csr' or 'sm_csr_1.5'" @@ -2362,7 +2363,7 @@ def __str__(self): self->LpDist(p, x.addressOf(0), output.addressOf(0), take_root); return output.forPython(); } - + PyObject *LpNearest(nupic::Real ## N2 p, PyObject *row, nupic::UInt ## N1 k =1, bool take_root =true) const { @@ -2402,7 +2403,7 @@ def __str__(self): return toReturn; } - PyObject* + PyObject* projRbf(nupic::Real ## N2 p, nupic::Real ## N2 k, PyObject* py_x) const { nupic::NumpyVectorT x(py_x), y(self->nRows()); @@ -2440,16 +2441,16 @@ NearestNeighbor_(32, 32, 32, 64) // GRAPH ALGORITHMS //-------------------------------------------------------------------------------- /* -%inline +%inline { //-------------------------------------------------------------------------------- PyObject* enumerate_sequences(nupic::Real threshold, - PyObject* g, - int cr=0, - int ns=0) + PyObject* g, + int cr=0, + int ns=0) { try { - void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; + void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; nupic::SparseMatrix > *arg1 = reinterpret_cast< nupic::SparseMatrix > * >(argp1); std::list > sequences; @@ -2479,7 +2480,7 @@ NearestNeighbor_(32, 32, 32, 64) PyObject* g) { try { - void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; + void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; nupic::SparseMatrix > *arg1 = reinterpret_cast< nupic::SparseMatrix > * >(argp1); std::list > comps; @@ -2545,7 +2546,7 @@ inline PyObject *_find_connected_components2(const TSM &sm) PyObject* cuthill_mckee(PyObject* g) { try { - void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; + void* argp1 = SWIG_Python_GetSwigThis(g)->ptr; nupic::SparseMatrix > *arg1 = reinterpret_cast< nupic::SparseMatrix > * >(argp1); nupic::NumpyVectorT p(arg1->nRows()); @@ -2573,7 +2574,7 @@ inline PyObject *_find_connected_components2(const TSM &sm) nupic::NumpyVectorT s(n, std::numeric_limits::max()); int nScores = int(c.end() - c.begin()); - for (int i = 0; i != nScores; ++i) + for (int i = 0; i != nScores; ++i) s.set(c.get(i), std::min(s.get(c.get(i)), d.get(i))); return s.forPython(); @@ -2588,7 +2589,7 @@ inline PyObject *_find_connected_components2(const TSM &sm) { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): if isinstance(args[0], basestring): self.this = _MATH.new__SM_01_32_16(1) self.fromCSR(args[0]) @@ -2600,7 +2601,7 @@ def __init__(self, *args): elif isinstance(args[0], _SM_01_32_16): self.this = _MATH.new__SM_01_32_16(1) self.copy(args[0]) - + def __str__(self): return self.toDense().__str__() @@ -2622,12 +2623,12 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); } else { - throw + throw std::runtime_error("Failed to read SparseBinaryMatrix state from string."); } } @@ -2675,7 +2676,7 @@ def __setstate__(self, inString): } return toReturn; - } + } inline void setAllNonZeros(nupic::UInt32 nrows, nupic::UInt16 ncols, PyObject* py_i, PyObject* py_j, bool sorted =true) @@ -2738,7 +2739,7 @@ def __setstate__(self, inString): self->nNonZerosPerCol(x.begin(), x.end()); return x.forPython(); } - + inline nupic::SparseMatrix nNonZerosPerBox(PyObject* box_i, PyObject* box_j) const { @@ -2746,11 +2747,11 @@ def __setstate__(self, inString): nupic::NumpyVectorT bounds_j(box_j); nupic::SparseMatrix result(bounds_i.size(), bounds_j.size()); self->nNonZerosPerBox(bounds_i.begin(), bounds_i.end(), - bounds_j.begin(), bounds_j.end(), + bounds_j.begin(), bounds_j.end(), result); return result; } - + inline PyObject* rowSums() const { nupic::NumpyVectorT x(self->nRows()); @@ -2828,11 +2829,11 @@ def __setstate__(self, inString): inline void fromDense(PyObject* py_m) { nupic::NumpyMatrixT m(py_m); - self->fromDense(m.rows(), m.columns(), + self->fromDense(m.rows(), m.columns(), m.addressOf(0,0), m.addressOf(0,0) + m.rows() * m.columns()); } - inline PyObject* toDense() const + inline PyObject* toDense() const { int dims[] = { self->nRows(), self->nCols() }; nupic::NumpyMatrixT out(dims); @@ -2939,7 +2940,7 @@ def __setstate__(self, inString): self->rowToDense(row, x.begin(), x.end()); return x.forPython(); } - + inline PyObject* getRow(nupic::UInt32 row) const { nupic::NumpyVectorT x(self->nCols()); @@ -3070,13 +3071,13 @@ def __setstate__(self, inString): } inline bool __eq__(const nupic::SparseBinaryMatrix& other) const - { - return self->equals(other); + { + return self->equals(other); } - + inline bool __ne__(const nupic::SparseBinaryMatrix& other) const - { - return ! self->equals(other); + { + return ! self->equals(other); } } // end extend nupic::SparseBinaryMatrix @@ -3086,7 +3087,7 @@ def __setstate__(self, inString): %extend nupic::SparseBinaryMatrix { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): if isinstance(args[0], basestring): self.this = _MATH.new__SM_01_32_32(1) self.fromCSR(args[0]) @@ -3102,7 +3103,7 @@ def __init__(self, *args): self.this = _MATH.new__SM_01_32_32(1) nz_i,nz_j,nz_v = args[0].getAllNonZeros(True) self.setAllNonZeros(args[0].nRows(), args[0].nCols(), nz_i, nz_j) - + def __str__(self): return self.toDense().__str__() @@ -3124,12 +3125,12 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); } else { - throw + throw std::runtime_error("Failed to read SparseBinaryMatrix state from string."); } } @@ -3177,7 +3178,7 @@ def __setstate__(self, inString): } return toReturn; - } + } inline void setAllNonZeros(nupic::UInt32 nrows, nupic::UInt32 ncols, PyObject* py_i, PyObject* py_j, bool sorted =true) @@ -3247,7 +3248,7 @@ def __setstate__(self, inString): nupic::NumpyVectorT bounds_j(box_j); nupic::SparseMatrix result(bounds_i.size(), bounds_j.size()); self->nNonZerosPerBox(bounds_i.begin(), bounds_i.end(), - bounds_j.begin(), bounds_j.end(), + bounds_j.begin(), bounds_j.end(), result); return result; } @@ -3329,11 +3330,11 @@ def __setstate__(self, inString): inline void fromDense(PyObject* py_m) { nupic::NumpyMatrixT m(py_m); - self->fromDense(m.rows(), m.columns(), + self->fromDense(m.rows(), m.columns(), m.addressOf(0,0), m.addressOf(0,0) + m.rows() * m.columns()); } - inline PyObject* toDense() const + inline PyObject* toDense() const { int dims[] = { static_cast(self->nRows()), static_cast(self->nCols()) }; nupic::NumpyMatrixT out(dims); @@ -3370,7 +3371,7 @@ def __setstate__(self, inString): return py_s.close(); } - bool fromPyString(PyObject *s) + bool fromPyString(PyObject *s) { Py_ssize_t n = 0; char *buf = 0; @@ -3537,7 +3538,7 @@ def __setstate__(self, inString): self->rightVecMaxAtNZ(m.begin(i), r.begin(i)); return r.forPython(); } - + PyObject* leftDenseMatSumAtNZ(PyObject* mIn) const { nupic::NumpyMatrixT m(mIn); @@ -3602,19 +3603,19 @@ def __setstate__(self, inString): } inline bool __eq__(const nupic::SparseBinaryMatrix& other) const - { - return self->equals(other); + { + return self->equals(other); } - + inline bool __ne__(const nupic::SparseBinaryMatrix& other) const - { - return ! self->equals(other); + { + return ! self->equals(other); } } // end extend nupic::SparseBinaryMatrix %pythoncode %{ - + #SM_01_32_16 = _SM_01_32_16 SM_01_32_32 = _SM_01_32_32 SparseBinaryMatrix = _SM_01_32_32 @@ -3631,7 +3632,7 @@ def __setstate__(self, inString): { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): if len(args) == 1: if isinstance(args[0], basestring): self.this = _MATH.new__SM_RLE_16_8() @@ -3640,8 +3641,8 @@ def __init__(self, *args): self.this = _MATH.new__SM_RLE_16_8() self.fromDense(numpy.asarray(args[0])) else: - self.this = _MATH.new__SM_RLE_16_8() - + self.this = _MATH.new__SM_RLE_16_8() + def __str__(self): return self.toDense().__str__() @@ -3663,7 +3664,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3694,11 +3695,11 @@ def __setstate__(self, inString): inline void fromDense(PyObject* py_m) { nupic::NumpyMatrixT m(py_m); - self->fromDense(m.rows(), m.columns(), + self->fromDense(m.rows(), m.columns(), m.addressOf(0,0), m.addressOf(0,0) + m.rows() * m.columns()); } - inline PyObject* toDense() const + inline PyObject* toDense() const { int dims[] = { self->nRows(), self->nCols() }; nupic::NumpyMatrixT out(dims); @@ -3718,7 +3719,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3748,7 +3749,7 @@ def __setstate__(self, inString): { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): if len(args) == 1: if isinstance(args[0], basestring): self.this = _MATH.new__SM_RLE_16_16() @@ -3757,8 +3758,8 @@ def __init__(self, *args): self.this = _MATH.new__SM_RLE_16_16() self.fromDense(numpy.asarray(args[0])) else: - self.this = _MATH.new__SM_RLE_16_16() - + self.this = _MATH.new__SM_RLE_16_16() + def __str__(self): return self.toDense().__str__() @@ -3780,7 +3781,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3811,11 +3812,11 @@ def __setstate__(self, inString): inline void fromDense(PyObject* py_m) { nupic::NumpyMatrixT m(py_m); - self->fromDense(m.rows(), m.columns(), + self->fromDense(m.rows(), m.columns(), m.addressOf(0,0), m.addressOf(0,0) + m.rows() * m.columns()); } - inline PyObject* toDense() const + inline PyObject* toDense() const { int dims[] = { self->nRows(), self->nCols() }; nupic::NumpyMatrixT out(dims); @@ -3835,7 +3836,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3867,7 +3868,7 @@ def __setstate__(self, inString): { %pythoncode %{ -def __init__(self, *args): +def __init__(self, *args): if len(args) == 1: if isinstance(args[0], basestring): self.this = _MATH.new__SM_RLE_32_32() @@ -3876,8 +3877,8 @@ def __init__(self, *args): self.this = _MATH.new__SM_RLE_32_32() self.fromDense(numpy.asarray(args[0])) else: - self.this = _MATH.new__SM_RLE_32_32() - + self.this = _MATH.new__SM_RLE_32_32() + def __str__(self): return self.toDense().__str__() @@ -3899,7 +3900,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3930,11 +3931,11 @@ def __setstate__(self, inString): inline void fromDense(PyObject* py_m) { nupic::NumpyMatrixT m(py_m); - self->fromDense(m.rows(), m.columns(), + self->fromDense(m.rows(), m.columns(), m.addressOf(0,0), m.addressOf(0,0) + m.rows() * m.columns()); } - inline PyObject* toDense() const + inline PyObject* toDense() const { int dims[] = { self->nRows(), self->nCols() }; nupic::NumpyMatrixT out(dims); @@ -3954,7 +3955,7 @@ def __setstate__(self, inString): { Py_ssize_t n = 0; char *buf = 0; - int res = PyString_AsStringAndSize(str, &buf, &n); + int res = PyString_AsStringAndSize(str, &buf, &n); if ((res == 0) && (n > 0)) { std::istringstream s(std::string(buf, n)); self->fromCSR(s); @@ -3980,7 +3981,7 @@ def __setstate__(self, inString): } // end extend nupic::SparseRLEMatrix %pythoncode %{ - + #SM_RLE_16_8 = _SM_RLE_16_8 #SM_RLE_16_16 = _SM_RLE_16_16 SM_RLE = _SM_RLE_32_32 @@ -4012,8 +4013,8 @@ def __setstate__(self, inString): %extend nupic::Gaussian2D { %pythoncode %{ - - def __init__(self, *args): + + def __init__(self, *args): this = _MATH.new__Gaussian2D_32(*args) try: self.this.append(this) @@ -4032,7 +4033,7 @@ def __setstate__(self, inString): } // end extend nupic::Gaussian2D %pythoncode %{ - + Gaussian_2D = _Gaussian2D_32 def Gaussian2D(*args, **keywords): @@ -4053,8 +4054,8 @@ def __setstate__(self, inString): %extend nupic::Set { %pythoncode %{ - - def __init__(self, *args): + + def __init__(self, *args): this = _MATH.new__Set() try: self.this.append(this) @@ -4085,7 +4086,7 @@ def __setstate__(self, inString): } // end extend nupic::Set %pythoncode %{ - + Set = _Set def Set(*args, **keywords): diff --git a/src/nupic/bindings/swig_proxy_preamble.py b/src/nupic/bindings/swig_proxy_preamble.py new file mode 100644 index 0000000000..d2cf39459c --- /dev/null +++ b/src/nupic/bindings/swig_proxy_preamble.py @@ -0,0 +1,44 @@ +# ---------------------------------------------------------------------- +# Numenta Platform for Intelligent Computing (NuPIC) +# Copyright (C) 2013-2016, Numenta, Inc. Unless you have an agreement +# with Numenta, Inc., for a separate license for this software code, the +# following terms and conditions apply: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero Public License version 3 as +# published by the Free Software Foundation. +# +# This program 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 Affero Public License for more details. +# +# You should have received a copy of the GNU Affero Public License +# along with this program. If not, see http://www.gnu.org/licenses. +# +# http://numenta.org/licenses/ +# ---------------------------------------------------------------------- + + +# The build prepends this module verbatim to each nupic.bindings python +# extension proxy module to load pycapnp's extension shared library in global +# scope before loading our own extension DLL (that doesn't contain capnproto +# code) so that our capnproto references will resolve against capnproto included +# in pycapnp. This ensures that the methods of the same capnproto build that +# creates the capnproto objects in nupic will be used on those objects from both +# nupic and nupic.bindings shared objects. + + +def _nupic_bindings_load_capnp_shared_object(): + import platform + # Windows nupic.bindings extensions include CAPNP_LITE capnproto subset and + # must not depend on pycapnp + if platform.system() != "Windows": + import ctypes, imp, os + capnpPackageDir = imp.find_module('capnp')[1] + capnpDLLPath=os.path.join(capnpPackageDir, 'lib', 'capnp.so') + ctypes.CDLL(capnpDLLPath, ctypes.RTLD_GLOBAL) + +_nupic_bindings_load_capnp_shared_object() + +del _nupic_bindings_load_capnp_shared_object