Use CMAKE_xx_COMPILER when building external dependencies (#636)
[dyninst.git] / cmake / Boost.cmake
1 #========================================================================================================
2 # Boost.cmake
3 #
4 # Configure Boost for Dyninst
5 #
6 #   ----------------------------------------
7 #
8 # Accepts the following CMake variables
9 #
10 # Boost_ROOT_DIR            - Hint directory that contains the Boost installation
11 # PATH_BOOST                - Alias for Boost_ROOT_DIR
12 # Boost_MIN_VERSION         - Minimum acceptable version of Boost
13 # Boost_USE_MULTITHREADED   - Use the multithreaded version of Boost
14 # Boost_USE_STATIC_RUNTIME  - Use libraries linked statically to the C++ runtime
15 #
16 # Options inherited from Modules/FindBoost.cmake that may be useful
17 #
18 # BOOST_INCLUDEDIR          - Hint directory that contains the Boost headers files
19 # BOOST_LIBRARYDIR          - Hint directory that contains the Boost library files
20 #
21 # Advanced options:
22 #
23 # Boost_DEBUG               - Enable debug output from FindBoost
24 # Boost_NO_SYSTEM_PATHS     - Disable searching in locations not specified by hint variables 
25 #
26 # Exports the following CMake cache variables
27 #
28 # Boost_ROOT_DIR            - Computed base directory the of Boost installation
29 # Boost_INCLUDE_DIRS        - Boost include directories
30 # Boost_INCLUDE_DIR         - Alias for Boost_INCLUDE_DIRS
31 # Boost_LIBRARY_DIRS        - Link directories for Boost libraries
32 # Boost_DEFINES             - Boost compiler definitions
33 # Boost_LIBRARIES           - Boost library files
34 # Boost_<C>_LIBRARY_RELEASE - Release libraries to link for component <C> (<C> is upper-case)
35 # Boost_<C>_LIBRARY_DEBUG   - Debug libraries to link for component <C>
36 # Boost_THREAD_LIBRARY      - The filename of the Boost thread library
37 # Boost_USE_MULTITHREADED   - Use the multithreaded version of Boost
38 # Boost_USE_STATIC_RUNTIME  - Use libraries linked statically to the C++ runtime
39 #
40 # NOTE:
41 # The exported Boost_ROOT_DIR can be different from the value provided by the user in the case that
42 # it is determined to build Boost from source. In such a case, Boost_ROOT_DIR will contain the
43 # directory of the from-source installation.
44 #
45 # See Modules/FindBoost.cmake for additional input and exported variables
46 #
47 #========================================================================================================
48
49 if(Boost_FOUND)
50   return()
51 endif()
52
53 # Need at least Boost-1.61 for filesytem components
54 set(_boost_min_version 1.61.0)
55
56 # Provide a default, if the user didn't specify
57 set(Boost_MIN_VERSION ${_boost_min_version} CACHE STRING "Minimum Boost version")
58
59 # Enforce minimum version
60 if(${Boost_MIN_VERSION} VERSION_LESS ${_boost_min_version})
61   message(FATAL_ERROR "Requested Boost-${Boost_MIN_VERSION} is less than minimum supported version (${_boost_min_version})")
62 endif()
63
64 # -------------- RUNTIME CONFIGURATION ----------------------------------------
65
66 # Use the multithreaded version of Boost
67 # NB: This _must_ be a cache variable as it
68 #     controls the tagged layout of Boost library names
69 set(Boost_USE_MULTITHREADED ON CACHE BOOL "Enable multithreaded Boost libraries")
70
71 # Don't use libraries linked statically to the C++ runtime
72 # NB: This _must_ be a cache variable as it
73 #     controls the tagged layout of Boost library names
74 set(Boost_USE_STATIC_RUNTIME OFF CACHE BOOL
75     "Enable usage of libraries statically linked to C++ runtime")
76
77 # If using multithreaded Boost, make sure Threads has been intialized
78 if(Boost_USE_MULTITHREADED AND NOT DEFINED CMAKE_THREAD_LIBS_INIT)
79   find_package(Threads)
80 endif()
81
82 # Enable debug output from FindBoost
83 set(Boost_DEBUG OFF CACHE BOOL "Enable debug output from FindBoost")
84
85 # -------------- PATHS --------------------------------------------------------
86
87 # By default, search system paths
88 set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "Disable searching in locations not specified by hint variables")
89
90 # A sanity check
91 # This must be done _before_ the cache variables are set
92 if(PATH_BOOST AND Boost_ROOT_DIR)
93   message(FATAL_ERROR "PATH_BOOST AND Boost_ROOT_DIR both specified. Please provide only one")
94 endif()
95
96 # Provide a default root directory
97 if(NOT PATH_BOOST AND NOT Boost_ROOT_DIR)
98   set(PATH_BOOST "/usr")
99 endif()
100
101 # Set the default location to look for Boost
102 set(Boost_ROOT_DIR ${PATH_BOOST} CACHE PATH "Base directory the of Boost installation")
103
104 # In FindBoost, Boost_ROOT_DIR is spelled BOOST_ROOT
105 set(BOOST_ROOT ${Boost_ROOT_DIR})
106
107 # -------------- COMPILER DEFINES ---------------------------------------------
108
109 set(_boost_defines)
110
111 # Disable auto-linking
112 list(APPEND _boost_defines -DBOOST_ALL_NO_LIB=1)
113
114 # Disable generating serialization code in boost::multi_index
115 list(APPEND _boost_defines -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
116   
117 # There are broken versions of MSVC that won't handle variadic templates
118 # correctly (despite the C++11 test case passing).
119 if(MSVC)
120   list(APPEND _boost_defines -DBOOST_NO_CXX11_VARIADIC_TEMPLATES)
121 endif()
122
123 set(Boost_DEFINES ${_boost_defines} CACHE STRING "Boost compiler defines")
124 add_definitions(${Boost_DEFINES})
125
126 # -------------- INTERNALS ----------------------------------------------------
127
128 # Disable Boost's own CMake as it's known to be buggy
129 # NB: This should not be a cache variable
130 set(Boost_NO_BOOST_CMAKE ON)
131
132 # The required Boost library components
133 # NB: These are just the ones that require compilation/linking
134 #     This should _not_ be a cache variable
135 set(_boost_components atomic chrono date_time filesystem system thread timer)
136
137 find_package(Boost ${Boost_MIN_VERSION} COMPONENTS ${_boost_components})
138
139 # -------------- SOURCE BUILD -------------------------------------------------
140
141 if(Boost_FOUND)
142   # Force the cache entries to be updated
143   # Normally, these would not be exported. However, we need them in the Testsuite
144   set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} CACHE PATH "Boost include directory" FORCE)
145   set(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIRS} CACHE PATH "Boost library directory" FORCE)
146   set(Boost_INCLUDE_DIR ${Boost_INCLUDE_DIR} CACHE PATH "Boost include directory" FORCE)
147   add_library(boost SHARED IMPORTED)
148 else()
149   # If we didn't find a suitable version on the system, then download one from the web
150   set(_boost_download_version "1.69.0")
151   
152   # If the user specifies a version other than _boost_download_version, use that version.
153   # NB: We know Boost_MIN_VERSION is >= _boost_min_version from earlier checks
154   if(${Boost_MIN_VERSION} VERSION_LESS ${_boost_download_version} OR
155      ${Boost_MIN_VERSION} VERSION_GREATER ${_boost_download_version})
156     set(_boost_download_version ${Boost_MIN_VERSION})
157   endif()
158   message(STATUS "${Boost_ERROR_REASON}")
159   message(STATUS "Attempting to build ${_boost_download_version} as external project")
160
161   # This is an internal consistency check. Normal users should not trip this since
162   # they cannot affect _boost_download_version.  
163   if(${_boost_download_version} VERSION_LESS ${Boost_MIN_VERSION})
164     message(FATAL_ERROR "Download version of Boost (${_boost_download_version}) "
165                         "is older than minimum allowed version (${Boost_MIN_VERSION})")
166   endif()
167   
168   if(Boost_USE_MULTITHREADED)
169     set(_boost_threading multi)
170   else()
171     set(_boost_threading single)
172   endif()
173   
174   if(Boost_USE_STATIC_RUNTIME)
175     set(_boost_runtime_link static)
176   else()
177     set(_boost_runtime_link shared)
178   endif()
179   
180   # Change the base directory
181   set(Boost_ROOT_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH "Base directory the of Boost installation" FORCE)
182
183   # Update the exported variables  
184   set(Boost_INCLUDE_DIRS ${Boost_ROOT_DIR}/include CACHE PATH "Boost include directory" FORCE)
185   set(Boost_LIBRARY_DIRS ${Boost_ROOT_DIR}/lib CACHE PATH "Boost library directory" FORCE)
186   set(Boost_INCLUDE_DIR ${Boost_INCLUDE_DIRS} CACHE PATH "Boost include directory" FORCE)
187   
188   set(BOOST_ARGS
189       --ignore-site-config
190       --link=static
191       --runtime-link=${_boost_runtime_link}
192       --threading=${_boost_threading})
193   if(WIN32)
194     # NB: We need to build both debug/release on windows
195     #     as we don't use CMAKE_BUILD_TYPE
196     set(BOOST_BOOTSTRAP call bootstrap.bat)
197     set(BOOST_BUILD ".\\b2")
198     if(CMAKE_SIZEOF_VOID_P STREQUAL "8")
199       list(APPEND BOOST_ARGS address-model=64)
200     endif()
201   else()
202     set(BOOST_BOOTSTRAP "./bootstrap.sh")
203     set(BOOST_BUILD "./b2")
204     if(CMAKE_BUILD_TYPE STREQUAL "Debug")
205       list(APPEND BOOST_ARGS variant=debug)
206     else()
207       list(APPEND BOOST_ARGS variant=release)
208     endif()
209   endif()
210
211   # Join the component names together to pass to --with-libraries during bootstrap
212   set(_boost_lib_names "")
213   foreach(c ${_boost_components})
214         # list(JOIN ...) is in cmake 3.12
215     string(CONCAT _boost_lib_names "${_boost_lib_names}${c},")
216   endforeach()
217
218   include(ExternalProject)
219   string(REPLACE "." "_" _boost_download_filename ${_boost_download_version})
220   ExternalProject_Add(
221     boost
222     PREFIX ${CMAKE_BINARY_DIR}/boost
223     URL http://downloads.sourceforge.net/project/boost/boost/${_boost_download_version}/boost_${_boost_download_filename}.zip
224     BUILD_IN_SOURCE 1
225     CONFIGURE_COMMAND CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} ${BOOST_BOOTSTRAP} --prefix=${Boost_ROOT_DIR} --with-libraries=${_boost_lib_names}
226     BUILD_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} install
227     INSTALL_COMMAND ""
228   )
229
230   if(WIN32)
231     # We need to specify different library names for debug vs release
232     set(Boost_LIBRARIES "")
233     foreach(c ${_boost_components})
234       list(APPEND Boost_LIBRARIES "optimized libboost_${c} debug libboost_${c}-gd ")
235       
236       # Also export cache variables for the file location of each library
237       string(TOUPPER ${c} _basename)
238       set(Boost_${_basename}_LIBRARY_RELEASE "${Boost_LIBRARY_DIRS}/libboost_${c}.dll" CACHE FILEPATH "" FORCE)
239       set(Boost_${_basename}_LIBRARY_DEBUG "${Boost_LIBRARY_DIRS}/libboost_${c}-gd.dll" CACHE FILEPATH "" FORCE)
240     endforeach()
241   else()
242     # Transform the component names into the library filenames
243     # e.g., system -> boost_system
244     set(Boost_LIBRARIES "")
245     foreach(c ${_boost_components})
246       list(APPEND Boost_LIBRARIES "${Boost_LIBRARY_DIRS}/libboost_${c}.so")
247       
248       # Also export cache variables for the file location of each library
249       string(TOUPPER ${c} _basename)
250       set(Boost_${_basename}_LIBRARY_RELEASE "${Boost_LIBRARY_DIRS}/libboost_${c}.so" CACHE FILEPATH "" FORCE)
251       set(Boost_${_basename}_LIBRARY_DEBUG "${Boost_LIBRARY_DIRS}/libboost_${c}.so" CACHE FILEPATH "" FORCE)
252     endforeach()
253   endif()
254 endif()
255
256 # -------------- EXPORT VARIABLES ---------------------------------------------
257
258 # Export Boost_THREAD_LIBRARY
259 list(FIND _boost_components "thread" _building_threads)
260 if(Boost_USE_MULTITHREADED AND ${_building_threads})
261   # On Windows, always use the debug version
262   # On Linux, we don't use tagged builds, so the debug/release filenames are the same
263   set(Boost_THREAD_LIBRARY ${Boost_THREAD_LIBRARY_DEBUG} CACHE FILEPATH "Boost thread library")
264 endif()
265
266 # Add the system thread library
267 if(Boost_USE_MULTITHREADED)
268   list(APPEND Boost_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
269 endif()
270
271 # Export the complete set of libraries
272 set(Boost_LIBRARIES ${Boost_LIBRARIES} CACHE FILEPATH "Boost library files" FORCE)
273
274 link_directories(${Boost_LIBRARY_DIRS})
275 include_directories(${Boost_INCLUDE_DIRS})
276
277 message(STATUS "Boost includes: ${Boost_INCLUDE_DIRS}")
278 message(STATUS "Boost library dirs: ${Boost_LIBRARY_DIRS}")
279 message(STATUS "Boost thread library: ${Boost_THREAD_LIBRARY}")
280 message(STATUS "Boost libraries: ${Boost_LIBRARIES}")
281
282 if(USE_COTIRE)
283   cotire(boost)
284 endif()