├── .eslintrc ├── .gitignore ├── .jshintrc ├── .npmignore ├── LICENSE ├── README.md ├── bin └── boost-lib ├── cmake ├── BoostLib.cmake ├── BoostLibInstaller.cmake ├── DownloadBoost.cmake └── GetBoostLibB2Args.cmake ├── lib ├── boostDownloader.js └── index.js ├── package.json └── tests ├── CMakeLists.txt └── main.cpp /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "arrowFunctions": true, 4 | "binaryLiterals": true, 5 | "blockBindings": true, 6 | "defaultParams": true, 7 | "forOf": true, 8 | "generators": true, 9 | "objectLiteralComputedProperties": true, 10 | "objectLiteralDuplicateProperties": true, 11 | "objectLiteralShorthandMethods": true, 12 | "objectLiteralShorthandProperties": true, 13 | "octalLiterals": true, 14 | "regexUFlag": true, 15 | "regexYFlag": true, 16 | "superInFunctions": true, 17 | "templateStrings": true, 18 | "unicodeCodePointEscapes": true, 19 | "globalReturn": true, 20 | "jsx": true 21 | }, 22 | "rules": { 23 | "no-underscore-dangle": false, 24 | "camelcase": false, 25 | "eol-last": false, 26 | "no-unused-vars": false, 27 | "quotes": false 28 | }, 29 | "env": { 30 | "node": true 31 | } 32 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Build 28 | build 29 | 30 | # Users Environment Variables 31 | .lock-wscript 32 | 33 | # IDE 34 | .idea 35 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "onevar": true, 3 | "esnext": true, 4 | "node": true, 5 | "browser": true 6 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | tests/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Gábor Mező aka unbornchikken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # boost-lib (MIT) 2 | 3 | # About 4 | 5 | boos-lib is a [Boost](http://www.boost.org/) dependency manager for [CMake.js](https://www.npmjs.com/package/cmake-js) based native modules. 6 | 7 | Everyone knowns about [Boost](http://www.boost.org/). It's the base of almost all C++ projects out there. But using it in native node addons was not so easy (until now). It's a huge download that can be accessible by navigating through the infamous Sourceforge Crapware Screens. After downloading, you will get the source files, bundled with Jam based build system that is impossible to integrate with node-gyp. 8 | 9 | So, if you wanted to create a native node module with Boost dependency, then you had the only option that to write down somewhere in the readme that your module requires Boost 1.x, and that's it. Your module consumers had to install Boost 1.x, compile it, set some environment variables pointing to their installation, and hope for that works with your module. There is not a miracle that there is no Boost based native node module exists ... yet. 10 | 11 | The good news there is hope. With CMake.js you can create native modules with Boost dependency. If your module consumer has the appropriate Boost version installed, then your module will use that. If not, then boost-lib module downloads Boost from Github, compiles the required libraries (only the required ones), and your module will use that installation. Everything is automatic and as fast as possible. A typical Boost installation with one required library takes about ~1.5 minutes, and that has to be done only once, any following module installations will use that deployment. 12 | 13 | #### CMake.js 14 | 15 | CMake.js is a Node.js/io.js native addon build tool which works exactly like node-gyp, but instead of gyp, it is based on [CMake build system](http://cmake.org). It's [on the npm](https://www.npmjs.com/package/cmake-js). 16 | 17 | # Installation 18 | 19 | ``` 20 | npm install boost-lib 21 | ``` 22 | 23 | # Usage 24 | 25 | In a nutshell. *(For more complete documentation please see [the tutorial](https://github.com/unbornchikken/cmake-js/wiki/TUTORIAL-04-Creating-CMake.js-based-native-modules-with-Boost-dependency).)* 26 | 27 | ## 1. Include 28 | 29 | Install boost-lib module from npm. 30 | 31 | ``` 32 | npm install boost-lib --save 33 | ``` 34 | 35 | Enter the following into your project's root CMakeLists.txt file to include BoostLib CMake module: 36 | 37 | ```cmake 38 | # Include BoostLib module 39 | SET(CMAKE_MODULE_PATH 40 | "${CMAKE_CURRENT_SOURCE_DIR}/node_modules/boost-lib/cmake") 41 | 42 | include(BoostLib) 43 | ``` 44 | 45 | ## 2. Require 46 | 47 | This makes `require_boost_libs` function available. It has two arguments: 48 | 49 | - in the first argument you have to specify required Boost library's semver specification like that you can use in package.json. For example to use Boost 1.58, enter `1.58.0`, to use Boost 1.57 or above, enter `">= 1.57.0"`. See [semver](https://www.npmjs.com/package/semver) modules's documentation for further details. 50 | - in the second argument you can specify required Boost's to-be-compiled libraries separated by semicolon. Leave blank if you need header only libraries. For example to depend on Boost.coroutine and Boost.DateTime, enter `coroutine;date_time`. 51 | 52 | Examples: 53 | 54 | Boost 1.57 or above required with thread and context libraries: 55 | 56 | ```cmake 57 | require_boost_libs(">= 1.57.0" thread;context) 58 | ``` 59 | 60 | Boost 1.58 required with header only libraries: 61 | 62 | ```cmake 63 | require_boost_libs(1.57.0 "") 64 | ``` 65 | 66 | Known to-be-build Boost libraries so far: 67 | 68 | - chrono 69 | - coroutine 70 | - context 71 | - filesystem 72 | - graph 73 | - locale 74 | - log 75 | - system 76 | - thread 77 | - timer 78 | - wave 79 | 80 | Their internal dependencies are handled automatically. So if you're requireing coroutine which depends on context and system, you don't have to sepcify them all, only coroutine. 81 | 82 | ## 3. Use 83 | 84 | Boost's include path should be registered by entering: 85 | 86 | ```cmake 87 | include_directories(${Boost_INCLUDE_DIRS}) 88 | ``` 89 | 90 | And you have to link your addon with Boost libraries: 91 | 92 | ```cmake 93 | target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB};${Boost_LIBRARIES}) 94 | ``` 95 | 96 | # Example and tutorial 97 | 98 | The [tutorial](https://github.com/unbornchikken/cmake-js/wiki/TUTORIAL-04-Creating-CMake.js-based-native-modules-with-Boost-dependency) is about making the [example module](https://github.com/unbornchikken/cmake-js-tut-04-boost-module), which can be downloaded from there: 99 | 100 | ``` 101 | git clone https://github.com/unbornchikken/cmake-js-tut-04-boost-module 102 | ``` 103 | -------------------------------------------------------------------------------- /bin/boost-lib: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | var log = require("npmlog"); 5 | var _ = require("lodash"); 6 | var boostLib = require("../"); 7 | var BoostDownloader = boostLib.BoostDownloader; 8 | var util = require("util"); 9 | var Bluebird = require("bluebird"); 10 | 11 | var version = require("../package").version; 12 | var logLevels = ["silly", "verbose", "info", "http", "warn", "error"]; 13 | var yargs = require("yargs") 14 | .usage("Boost dependency resolver for CMake.js - v" + version + "\n\nUsage: $0 [] [options]") 15 | .version(function () { 16 | return version; 17 | }) 18 | .command("download", "Downloads specified Boost version if needed") 19 | .options({ 20 | h: { 21 | alias: "help", 22 | demand: false, 23 | describe: "show this screen", 24 | type: "boolean" 25 | }, 26 | l: { 27 | alias: "log-level", 28 | demand: false, 29 | describe: "sets log level (" + logLevels.join(", ") + "), default is info", 30 | type: "string" 31 | }, 32 | V: { 33 | alias: "boost-version", 34 | demand: false, 35 | describe: "Boost version", 36 | type: "string" 37 | } 38 | }); 39 | var argv = yargs.argv; 40 | 41 | // If help, then print and exit: 42 | 43 | if (argv.h) { 44 | console.info(yargs.help()); 45 | return; 46 | } 47 | 48 | // Setup log level: 49 | 50 | if (argv.l && _.contains(logLevels, argv.l)) { 51 | log.level = argv.l; 52 | log.resume(); 53 | } 54 | 55 | log.silly("CON", "argv:"); 56 | log.silly("CON", util.inspect(argv)); 57 | 58 | log.verbose("CON", "Parsing arguments"); 59 | 60 | var options = { 61 | version: argv.V 62 | }; 63 | 64 | log.verbose("CON", "options:"); 65 | log.verbose("CON", util.inspect(options)); 66 | 67 | var command = _.first(argv._); 68 | 69 | log.verbose("CON", "Running command: " + command); 70 | 71 | function ifCommand(c, f) { 72 | if (c === command) { 73 | f(); 74 | return true; 75 | } 76 | return false; 77 | } 78 | 79 | function exitOnError(promise) { 80 | try { 81 | if (_.isFunction(promise)) { 82 | promise = promise(); 83 | } 84 | } 85 | catch (e) { 86 | promise = Bluebird.reject(e); 87 | } 88 | promise.catch(function(e) { 89 | if (log.level === "verbose" || log.level === "silly") { 90 | log.error("OMG", e.stack); 91 | } 92 | else { 93 | log.error("OMG", e.message); 94 | } 95 | process.exit(1); 96 | }); 97 | } 98 | 99 | function download() { 100 | exitOnError(function() { 101 | return new BoostDownloader(options).ensureDownloaded() 102 | .then(function(path) { 103 | console.info(path); 104 | }); 105 | }); 106 | } 107 | 108 | var done = ifCommand("download", download); 109 | if (!done) { 110 | if (command) { 111 | log.error("OMG", "Unknown command: " + command); 112 | } 113 | else { 114 | log.error("OMG", "Command expected."); 115 | } 116 | process.exit(1); 117 | } 118 | -------------------------------------------------------------------------------- /cmake/BoostLib.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | include(BoostLibInstaller) 4 | 5 | function(require_boost_libs req_boost_version req_boost_libs) 6 | message(STATUS "Require Boost Libs module started.") 7 | message(STATUS "Required Boost version: ${req_boost_version}") 8 | message(STATUS "Required libs: ${req_boost_libs}") 9 | 10 | # Finding installed boost version 11 | string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+$" m "${req_boost_version}") 12 | if(NOT m STREQUAL "") 13 | find_package(Boost "${req_boost_version}" COMPONENTS "${req_boost_libs}") 14 | endif() 15 | 16 | if(Boost_FOUND) 17 | message(STATUS "Boost package found.") 18 | else(Boost_FOUND) 19 | boost_lib_installer("${req_boost_version}" "${req_boost_libs}") 20 | message(STATUS "Boost installed.") 21 | endif(Boost_FOUND) 22 | 23 | message(STATUS "Boost Include dirs: ${Boost_INCLUDE_DIRS}") 24 | message(STATUS "Boost Libraries: ${Boost_LIBRARIES}") 25 | 26 | # Results: 27 | set(Boost_FOUND ${Boost_FOUND} PARENT_SCOPE) 28 | set(Boost_INCLUDE_DIRS "${Boost_INCLUDE_DIRS}" PARENT_SCOPE) 29 | set(Boost_LIBRARIES "${Boost_LIBRARIES}" PARENT_SCOPE) 30 | endfunction(require_boost_libs) -------------------------------------------------------------------------------- /cmake/BoostLibInstaller.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | include(ExternalProject) 4 | include(GetBoostLibB2Args) 5 | include(DownloadBoost) 6 | 7 | # Known dependencies 8 | set(chrono_dep system) 9 | set(coroutine_dep context system) 10 | set(context_dep thread) 11 | set(filesystem_dep system) 12 | set(graph_dep regex) 13 | set(locale_dep system) 14 | set(log_dep chrono date_time filesystem thread) 15 | set(thread_dep chrono) 16 | set(timer_dep chrono) 17 | set(wave_dep chrono date_time filesystem thread) 18 | 19 | function(boost_lib_installer req_boost_version req_boost_libs) 20 | message(STATUS "Boost Lib Installer starting.") 21 | 22 | # Download 23 | download_boost("${req_boost_version}") 24 | get_filename_component(req_boost_version "${install_dir}" NAME) 25 | message(STATUS "Boost path: ${install_dir}") 26 | message(STATUS "Boost version: ${req_boost_version}") 27 | string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\." m "${req_boost_version}") 28 | set(lib_postfix "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}") 29 | message(STATUS "Boost library postfix: ${lib_postfix}") 30 | 31 | # Bootstrap 32 | if(WIN32) 33 | set(bootstrap bootstrap.bat) 34 | set(b2_command b2.exe) 35 | file(TO_CMAKE_PATH "${install_dir}/b2.exe" b2_path) 36 | else(WIN32) 37 | set(bootstrap ./bootstrap.sh) 38 | set(b2_command ./b2) 39 | file(TO_CMAKE_PATH "${install_dir}/b2" b2_path) 40 | endif(WIN32) 41 | if (NOT EXISTS "${b2_path}") 42 | message(STATUS "Invoking ${install_dir}/tools/build/${bootstrap}") 43 | execute_process(COMMAND "${bootstrap}" WORKING_DIRECTORY "${install_dir}/tools/build" RESULT_VARIABLE err OUTPUT_VARIABLE err_msg OUTPUT_QUIET) 44 | if(err) 45 | message(FATAL_ERROR "Bootstrap error:\n${err_msg}") 46 | endif(err) 47 | message(STATUS "Invoking ${install_dir}/${bootstrap}") 48 | execute_process(COMMAND "${bootstrap}" WORKING_DIRECTORY "${install_dir}" RESULT_VARIABLE err OUTPUT_VARIABLE err_msg OUTPUT_QUIET) 49 | if(err) 50 | message(FATAL_ERROR "Bootstrap error:\n${err_msg}") 51 | endif(err) 52 | else() 53 | message(STATUS "b2 executable found.") 54 | endif() 55 | 56 | # Process libs 57 | if(req_boost_libs) 58 | if(MSVC) 59 | if(CMAKE_CL_64 EQUAL 1) 60 | set(stage_dir stage64) 61 | else() 62 | set(stage_dir stage32) 63 | endif() 64 | else() 65 | set(stage_dir stage) 66 | endif() 67 | 68 | get_boots_lib_b2_args() 69 | message(STATUS "b2 args: ${b2Args}") 70 | 71 | # Resolve dependency tree 72 | foreach(i RANGE 4) 73 | foreach(lib ${req_boost_libs}) 74 | list(APPEND req_boost_libs2 ${lib}) 75 | list(APPEND req_boost_libs2 ${${lib}_dep}) 76 | endforeach() 77 | list(REMOVE_DUPLICATES req_boost_libs2) 78 | set(req_boost_libs "${req_boost_libs2}") 79 | endforeach() 80 | 81 | foreach(lib ${req_boost_libs}) 82 | message(STATUS "Resolving Boost library: ${lib}") 83 | 84 | if (EXISTS "${install_dir}/libs/${lib}/build/") 85 | # Has source 86 | 87 | # Setup variables 88 | set(jam_lib boost_${lib}_jam) 89 | set(boost_lib boost_${lib}) 90 | if(lib STREQUAL "test") 91 | set(lib_name unit_test_framework) 92 | else() 93 | set(lib_name ${lib}) 94 | endif() 95 | 96 | if(MSVC) 97 | if(MSVC11) 98 | set(compiler_name vc110) 99 | elseif(MSVC12) 100 | set(compiler_name vc120) 101 | elseif(MSVC14) 102 | set(compiler_name vc140) 103 | endif() 104 | 105 | set(debug_lib_path "${install_dir}/${stage_dir}/lib/libboost_${lib_name}-${compiler_name}-mt-gd-${lib_postfix}.lib") 106 | set(lib_path "${install_dir}/${stage_dir}/lib/libboost_${lib_name}-${compiler_name}-mt-${lib_postfix}.lib") 107 | else() 108 | if((CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "") OR (NOT DEFINED CMAKE_BUILD_TYPE)) 109 | set(lib_path "${install_dir}/${stage_dir}/lib/libboost_${lib_name}-mt-d.a") 110 | else() 111 | set(lib_path "${install_dir}/${stage_dir}/lib/libboost_${lib_name}-mt.a") 112 | endif() 113 | endif() 114 | 115 | # Create lib 116 | if(EXISTS ${lib_path}) 117 | message(STATUS "Library ${lib} already built.") 118 | # Dummy project: 119 | ExternalProject_Add( 120 | "${jam_lib}" 121 | STAMP_DIR "${CMAKE_BINARY_DIR}/boost-${req_boost_version}" 122 | SOURCE_DIR "${install_dir}" 123 | BINARY_DIR "${install_dir}" 124 | CONFIGURE_COMMAND "" 125 | BUILD_COMMAND "" 126 | INSTALL_COMMAND "" 127 | BUILD_BYPRODUCTS "${lib_path}" 128 | LOG_BUILD OFF) 129 | else() 130 | message(STATUS "Setting up external project to build ${lib}.") 131 | ExternalProject_Add( 132 | "${jam_lib}" 133 | STAMP_DIR "${CMAKE_BINARY_DIR}/boost-${req_boost_version}" 134 | SOURCE_DIR "${install_dir}" 135 | BINARY_DIR "${install_dir}" 136 | CONFIGURE_COMMAND "" 137 | BUILD_COMMAND "${b2_command}" "${b2Args}" --with-${lib} 138 | INSTALL_COMMAND "" 139 | BUILD_BYPRODUCTS "${lib_path}" 140 | LOG_BUILD ON) 141 | endif() 142 | 143 | add_library(${boost_lib} STATIC IMPORTED GLOBAL) 144 | 145 | if(MSVC) 146 | set_target_properties(${boost_lib} PROPERTIES 147 | IMPORTED_LOCATION_DEBUG "${debug_lib_path}" 148 | IMPORTED_LOCATION "${lib_path}" 149 | LINKER_LANGUAGE CXX) 150 | else() 151 | set_target_properties(${boost_lib} PROPERTIES 152 | IMPORTED_LOCATION "${lib_path}" 153 | LINKER_LANGUAGE CXX) 154 | endif() 155 | 156 | # Exlude it from all 157 | set_target_properties(${jam_lib} ${boost_lib} PROPERTIES LABELS Boost EXCLUDE_FROM_ALL TRUE) 158 | 159 | # Setup dependencies 160 | add_dependencies(${boost_lib} ${jam_lib}) 161 | foreach(dep_lib ${${lib}_dep}) 162 | message(STATUS "Setting ${boost_lib} dependent on boost_${dep_lib}") 163 | add_dependencies(${boost_lib} boost_${dep_lib}) 164 | endforeach() 165 | 166 | list(APPEND boost_libs ${boost_lib}) 167 | 168 | endif() 169 | 170 | endforeach() 171 | endif(req_boost_libs) 172 | 173 | if(boost_libs) 174 | message(STATUS "Boost libs scheduled for build: ${boost_libs}") 175 | set(Boost_LIBRARIES "${boost_libs}" PARENT_SCOPE) 176 | set(Boost_LIBRARY_DIR "${install_dir}/${stage_dir}/lib/" CACHE STRING "" FORCE) 177 | else() 178 | set(Boost_LIBRARIES "" PARENT_SCOPE) 179 | set(Boost_LIBRARY_DIR "" CACHE STRING "" FORCE) 180 | endif() 181 | 182 | # b2 headers 183 | if(NOT EXISTS ${install_dir}/boost/) 184 | message(STATUS "Generating headers ...") 185 | execute_process(COMMAND ${b2_command} --ignore-site-config headers WORKING_DIRECTORY ${install_dir} RESULT_VARIABLE err OUTPUT_VARIABLE err_msg) 186 | if(err) 187 | message(FATAL_ERROR "b2 error:\n${err_msg}") 188 | endif(err) 189 | else() 190 | message(STATUS "Headers found.") 191 | endif() 192 | 193 | set(Boost_INCLUDE_DIR "${install_dir}" CACHE STRING "" FORCE) 194 | set(Boost_INCLUDE_DIRS "${install_dir}" PARENT_SCOPE) 195 | set(Boost_FOUND TRUE PARENT_SCOPE) 196 | 197 | endfunction(boost_lib_installer) -------------------------------------------------------------------------------- /cmake/DownloadBoost.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | function(download_boost version) 4 | find_file(cwd DownloadBoost.cmake PATHS ${CMAKE_MODULE_PATH}) 5 | get_filename_component(cwd "${cwd}" DIRECTORY) 6 | file(TO_CMAKE_PATH "${cwd}/../bin/boost-lib" boost-lib) 7 | message(STATUS "Invoking boost-lib to download Boost ${version}.") 8 | execute_process(COMMAND node "${boost-lib}" download "-V=${version}" RESULT_VARIABLE err OUTPUT_VARIABLE path) 9 | if(err) 10 | message(FATAL_ERROR "Download error.") 11 | endif(err) 12 | string(STRIP "${path}" path) 13 | file(TO_CMAKE_PATH "${path}" path) 14 | set(install_dir ${path} PARENT_SCOPE) 15 | endfunction(download_boost) -------------------------------------------------------------------------------- /cmake/GetBoostLibB2Args.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | function(get_boots_lib_b2_args) 4 | if(MSVC) 5 | if(CMAKE_CL_64 EQUAL 1) 6 | set(stage_dir stage64) 7 | else() 8 | set(stage_dir stage32) 9 | endif() 10 | else() 11 | set(stage_dir stage) 12 | endif() 13 | 14 | set(b2Args link=static 15 | threading=multi 16 | runtime-link=shared 17 | --build-dir=Build 18 | stage 19 | --stagedir=${stage_dir} 20 | -d+2 21 | --hash 22 | --ignore-site-config) 23 | 24 | message(STATUS "Generating b2 args.") 25 | 26 | if(NOT MSVC) 27 | if((CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "") OR (NOT DEFINED CMAKE_BUILD_TYPE)) 28 | message(STATUS "\tvariant=debug") 29 | list(APPEND b2Args "variant=debug") 30 | else() 31 | message(STATUS "\tvariant=release") 32 | list(APPEND b2Args "variant=release") 33 | endif() 34 | endif(NOT MSVC) 35 | 36 | if(CMAKE_BUILD_TYPE STREQUAL "ReleaseNoInline") 37 | list(APPEND b2Args "cxxflags=${RELEASENOINLINE_FLAGS}") 38 | endif() 39 | if(CMAKE_BUILD_TYPE STREQUAL "DebugLibStdcxx") 40 | list(APPEND b2Args define=_GLIBCXX_DEBUG) 41 | endif() 42 | 43 | # Set up platform-specific b2 (bjam) command line arguments 44 | if(MSVC) 45 | if(MSVC11) 46 | list(APPEND b2Args toolset=msvc-11.0) 47 | elseif(MSVC12) 48 | list(APPEND b2Args toolset=msvc-12.0) 49 | elseif(MSVC14) 50 | list(APPEND b2Args toolset=msvc-14.0) 51 | endif() 52 | 53 | list(APPEND b2Args 54 | define=_BIND_TO_CURRENT_MFC_VERSION=1 55 | define=_BIND_TO_CURRENT_CRT_VERSION=1 56 | --layout=versioned) 57 | 58 | if(CMAKE_CL_64 EQUAL 1) 59 | list(APPEND b2Args address-model=64) 60 | else() 61 | list(APPEND b2Args address-model=32) 62 | endif() 63 | elseif(APPLE) 64 | list(APPEND b2Args toolset=clang cxxflags=-fPIC cxxflags=-std=c++11 cxxflags=-stdlib=libc++ 65 | linkflags=-stdlib=libc++ architecture=combined address-model=32_64 --layout=tagged) 66 | elseif(UNIX) 67 | list(APPEND b2Args --layout=tagged -sNO_BZIP2=1) 68 | if(ANDROID_BUILD) 69 | configure_file("${CMAKE_SOURCE_DIR}/tools/android/user-config.jam.in" "${BoostSourceDir}/tools/build/src/user-config.jam") 70 | list(APPEND b2Args toolset=gcc-android target-os=linux) 71 | else() 72 | list(APPEND b2Args cxxflags=-fPIC cxxflags=-std=c++11) 73 | # Need to configure the toolset based on whatever version CMAKE_CXX_COMPILER is 74 | # string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" ToolsetVer "${CMAKE_CXX_COMPILER_VERSION}") 75 | if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") 76 | # list(APPEND b2Args toolset=clang-${ToolsetVer}) 77 | list(APPEND b2Args toolset=clang) 78 | if(HAVE_LIBC++) 79 | list(APPEND b2Args cxxflags=-stdlib=libc++ linkflags=-stdlib=libc++) 80 | endif() 81 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 82 | # list(APPEND b2Args toolset=gcc-${ToolsetVer}) 83 | list(APPEND b2Args toolset=gcc) 84 | endif() 85 | endif() 86 | endif() 87 | 88 | set(b2Args "${b2Args}" PARENT_SCOPE) 89 | endfunction(get_boots_lib_b2_args) 90 | -------------------------------------------------------------------------------- /lib/boostDownloader.js: -------------------------------------------------------------------------------- 1 | var _ = require("lodash"); 2 | var cmakejs = require("cmake-js"); 3 | var CMLog = cmakejs.CMLog; 4 | var Bluebird = require("bluebird"); 5 | var fs = Bluebird.promisifyAll(require("fs-extra")); 6 | var semver = require("semver"); 7 | var path = require("path"); 8 | var environment = cmakejs.environment; 9 | var zlib = require("zlib"); 10 | var tar = require("tar"); 11 | var request = require("request"); 12 | var exec = require('child_process').exec; 13 | 14 | function downloadTo(url, result) { 15 | return new Bluebird(function (resolve, reject) { 16 | request 17 | .get(url) 18 | .on('error', function (err) { reject(err); }) 19 | .pipe(result); 20 | 21 | result.once("finish", function () { resolve(); }); 22 | }); 23 | } 24 | 25 | function BoostDownloader(options) { 26 | this.options = options; 27 | this.dir = path.join(environment.home, ".cmake-js", "boost"); 28 | this.version = options.version; 29 | if (!this.version) { 30 | throw new Error("Version option expected!"); 31 | } 32 | this.log = new CMLog(this.options); 33 | } 34 | 35 | BoostDownloader.prototype.ensureDownloaded = function () { 36 | var self = this; 37 | self.log.info("BOOST", "Searching for Boost " + self.version + " in '" + self.dir + "'."); 38 | return fs.mkdirpAsync(self.dir) 39 | .then(function () { 40 | return fs.readdirAsync(self.dir) 41 | }) 42 | .then(function (files) { 43 | self.log.silly("BOOST", files.length + " entries found."); 44 | var foundDir = null; 45 | _.forEach(files, function (entry) { 46 | var fullPath = path.join(self.dir, entry); 47 | var stat = fs.lstatSync(fullPath); 48 | if (stat.isDirectory()) { 49 | var sv = semver.valid(entry); 50 | if (sv) { 51 | self.log.verbose("BOOST", "Comparing version: " + sv); 52 | if (semver.satisfies(sv, self.version)) { 53 | foundDir = fullPath; 54 | return false; 55 | } 56 | } 57 | } 58 | }); 59 | return foundDir; 60 | }) 61 | .then(function (foundDir) { 62 | if (foundDir) { 63 | self.log.info("BOOST", "Boost found in '" + foundDir + "'."); 64 | 65 | var stat; 66 | 67 | // Is this already initialized? 68 | try { 69 | stat = fs.statSync(path.join(foundDir, environment.isWin ? "b2.exe" : "b2")); 70 | if (stat.isFile()) { 71 | self.log.verbose("BOOST", "Deployment already initialized."); 72 | return foundDir; 73 | } 74 | } 75 | catch (e) { 76 | } 77 | 78 | // Is this already downloaded? 79 | try { 80 | stat = fs.statSync(path.join(foundDir, environment.isWin ? "bootstrap.bat" : "bootstrap.sh")); 81 | if (stat.isFile()) { 82 | self.log.verbose("BOOST", "Deployment already downloaded. Checking submodules."); 83 | return self._downloadSubmodules(semver.valid(path.basename(foundDir)), foundDir) 84 | .then(function () { 85 | return foundDir; 86 | }); 87 | } 88 | } 89 | catch (e) { 90 | } 91 | } 92 | 93 | return self._download(); 94 | }); 95 | }; 96 | 97 | BoostDownloader.prototype._download = function () { 98 | var self = this; 99 | self.log.verbose("BOOST", "Getting Boost releases."); 100 | var command = "git ls-remote --tags https://github.com/boostorg/boost.git"; 101 | return new Bluebird(function (resolve, reject) { 102 | exec(command, function (err, stdout, stderr) { 103 | if (err) { 104 | reject(err); 105 | return; 106 | } 107 | if (stdout) { 108 | var output = stdout.split("\n"); 109 | var downloadVersion = null; 110 | if (output && output.length) { 111 | output.reverse(); 112 | _.forEach(output, function (line) { 113 | var parts = line.split(/\s+/); 114 | if (parts.length === 2) { 115 | var relVersion = parts[1].substr("refs/tags/boost-".length); 116 | 117 | // Fix error when a tag is not a valid semver, by validating first 118 | var sv = semver.valid(relVersion); 119 | if (sv) { 120 | self.log.verbose("BOOST", "Comparing version: " + relVersion); 121 | if (semver.satisfies(sv, self.version)) { 122 | self.log.verbose("BOOST", "Version OK."); 123 | downloadVersion = relVersion; 124 | return false; 125 | } 126 | } 127 | } 128 | }); 129 | } 130 | if (downloadVersion) { 131 | self._downloadVersion(downloadVersion) 132 | .then(function (result) { 133 | resolve(result); 134 | }) 135 | .catch(function (e) { 136 | reject(e); 137 | }); 138 | return; 139 | } 140 | } 141 | reject(new Error("No releases found.")); 142 | }); 143 | }); 144 | }; 145 | 146 | BoostDownloader.prototype._downloadVersion = function (version) { 147 | var self = this; 148 | var downloadUrl = "https://github.com/boostorg/boost/archive/boost-" + version + ".tar.gz"; 149 | var internalPath = path.join(this.dir, version); 150 | self.log.http("BOOST", "Downloading: " + downloadUrl); 151 | 152 | var gunzip = zlib.createGunzip(); 153 | var extracter = new tar.Extract({ 154 | path: internalPath, 155 | strip: 1 156 | }); 157 | 158 | return fs.mkdirpAsync(internalPath) 159 | .then(function () { 160 | return new Bluebird(function (resolve, reject) { 161 | gunzip.once("error", function (err) { reject(err); }); 162 | extracter.once("end", function () { 163 | self.log.verbose("BOOST", "Downloaded: " + internalPath); 164 | resolve(); 165 | }); 166 | extracter.once("error", function (err) { reject(err); }); 167 | request 168 | .get(downloadUrl) 169 | .on("error", function (err) { reject(err); }) 170 | .pipe(gunzip) 171 | .on("error", function (err) { reject(err); }) 172 | .pipe(extracter) 173 | .on("error", function (err) { reject(err); }); 174 | }); 175 | }) 176 | .then(function () { 177 | return self._downloadSubmodules(version, internalPath); 178 | }) 179 | .then(function () { 180 | return internalPath; 181 | }); 182 | }; 183 | 184 | BoostDownloader.prototype._downloadSubmodules = function (version, internalPath) { 185 | var self = this; 186 | var task = []; 187 | self.log.verbose("BOOST", "Checking tools."); 188 | task.push(self._downloadSubmo(version, path.join(internalPath, "tools"), "build")); 189 | task.push(self._downloadSubmo(version, path.join(internalPath, "tools"), "inspect")); 190 | function downloadAt(libsPath, prefix) { 191 | var dirName = path.basename(libsPath); 192 | prefix = prefix || ""; 193 | self.log.info("BOOST", "Downloading submodules of director '" + dirName + "'."); 194 | var done = 0; 195 | task.push( 196 | fs.readdirAsync(libsPath) 197 | .then(function (libs) { 198 | self.log.verbose("BOOST", "Checking " + libs.length + " libs."); 199 | var libTasks = []; 200 | libs.forEach(function (lib) { 201 | var fullLibPath = path.join(libsPath, lib); 202 | var stat = fs.lstatSync(fullLibPath); 203 | if (stat.isDirectory()) { 204 | libTasks.push( 205 | self._downloadSubmo(version, libsPath, lib, prefix) 206 | .then(function (internalPath) { 207 | ++done; 208 | if (internalPath) { 209 | self.log.info("BOOST", ((done / libTasks.length) * 100).toFixed(1) + "% - submodule " + dirName + "/" + lib + " downloaded."); 210 | } 211 | else { 212 | self.log.verbose("BOOST", ((done / libTasks.length) * 100).toFixed(1) + "% - submodule " + dirName + "/" + lib + " exists."); 213 | } 214 | }) 215 | .catch(function (e) { 216 | ++done; 217 | self.log.info("BOOST", ((done / libTasks.length) * 100).toFixed(1) + "% - submodule " + dirName + "/" + lib + " download error."); 218 | self.log.silly("BOOST", "Error: " + e.stack); 219 | })); 220 | } 221 | }); 222 | return Bluebird.all(libTasks); 223 | })); 224 | return Bluebird.all(task); 225 | } 226 | 227 | return downloadAt(path.join(internalPath, "libs")) 228 | .then(function () { 229 | return downloadAt(path.join(internalPath, "libs", "numeric"), "numeric_"); 230 | }); 231 | }; 232 | 233 | BoostDownloader.prototype._downloadSubmo = function (version, internalPath, name, prefix) { 234 | var self = this; 235 | prefix = prefix || ""; 236 | internalPath = path.join(internalPath, name); 237 | 238 | return fs.readdirAsync(internalPath) 239 | .then(function (entries) { 240 | if (entries && entries.length) { 241 | return; 242 | } 243 | 244 | var downloadUrl = "https://github.com/boostorg/" + prefix + name + "/archive/boost-" + version + ".tar.gz"; 245 | self.log.http("BOOST", "Downloading: " + downloadUrl); 246 | 247 | var gunzip = zlib.createGunzip(); 248 | var extracter = new tar.Extract({ 249 | path: internalPath, 250 | strip: 1 251 | }); 252 | 253 | return new Bluebird(function (resolve, reject) { 254 | gunzip.once("error", function (err) { reject(err); }); 255 | extracter.once("end", function () { 256 | resolve(internalPath); 257 | }); 258 | extracter.once("error", function (err) { reject(err); }); 259 | request 260 | .get(downloadUrl) 261 | .on("error", function (err) { reject(err); }) 262 | .pipe(gunzip) 263 | .on("error", function (err) { reject(err); }) 264 | .pipe(extracter) 265 | .on("error", function (err) { reject(err); }); 266 | }); 267 | }); 268 | }; 269 | 270 | module.exports = BoostDownloader; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | BoostDownloader: require("./boostDownloader") 5 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boost-lib", 3 | "version": "0.11.3", 4 | "description": "Boost dependency manager for CMake.js based native modules", 5 | "license": "MIT", 6 | "keywords": [ 7 | "native", 8 | "addon", 9 | "module", 10 | "c", 11 | "c++", 12 | "bindings", 13 | "build", 14 | "cmake", 15 | "nw.js", 16 | "boost" 17 | ], 18 | "author": "Gábor Mező aka unbornchikken", 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/unbornchikken/boost-lib.git" 22 | }, 23 | "bin": "./bin/boost-lib", 24 | "main": "./lib/index.js", 25 | "engines": { 26 | "node": ">= 0.10.0", 27 | "iojs": ">= 1.0.0" 28 | }, 29 | "dependencies": { 30 | "bluebird": "*", 31 | "debug": "*", 32 | "fs-extra": "0", 33 | "lodash": "*", 34 | "memory-stream": "0", 35 | "npmlog": "1", 36 | "request": "2", 37 | "semver": "*", 38 | "tar": "1", 39 | "url-join": "0", 40 | "yargs": "3" 41 | }, 42 | "peerDependencies": { 43 | "cmake-js": "^3.0.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | message(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/) 4 | SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/) 5 | include(BoostLib) 6 | 7 | if(CMAKE_CL_64 EQUAL 0) 8 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") 9 | endif() 10 | 11 | if(UNIX) 12 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 13 | endif() 14 | 15 | require_boost_libs(1.58.0 coroutine;optional) 16 | 17 | include_directories(${Boost_INCLUDE_DIRS}) 18 | file(GLOB src "main.cpp") 19 | add_executable(test-boost ${src}) 20 | target_link_libraries(test-boost ${Boost_LIBRARIES}) -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright Oliver Kowalke 2009. 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | int main() 13 | { 14 | boost::coroutines::asymmetric_coroutine< int >::pull_type source( 15 | [&]( boost::coroutines::asymmetric_coroutine< int >::push_type & sink) { 16 | int first = 1, second = 1; 17 | sink( first); 18 | sink( second); 19 | for ( int i = 0; i < 8; ++i) 20 | { 21 | int third = first + second; 22 | first = second; 23 | second = third; 24 | sink( third); 25 | } 26 | }); 27 | 28 | for ( auto i : source) 29 | std::cout << i << " "; 30 | 31 | std::cout << "\nDone" << std::endl; 32 | 33 | return EXIT_SUCCESS; 34 | } --------------------------------------------------------------------------------