3
votes

I have a little Hello, World style program which I'd like to work on more in end-to-end fashion using CMake. In this case it means I could download Boost libraries, compile them and finally compile my little Hello, World and link the Boost libraries to it.

The Directory layout looks like this currently

cmaketest
|- build //I would like to have here the CMake generated IDE files.
|- src
   |- main.cpp
   |- hello.cpp
   |- hello.hpp
|- depends //I would like to have here the built Boost libraries and headers.
|- downloads //This contains the downloaded zip file.
|- temp //Temporary files.

I have the following CMakeLists.txt, and currently I generate the Visual Studio 2015 project files like so: cmake build -G "Visual Studio 14 2015 Win64". All good and well, I'll start the solution, CMake complains it can't find Boost, goes to download it starts to build (in the following code I've set to fetch a file previously acquired). But then after building for a while, the problems emerge...

  1. The Boost files seem to appear in \cmaketest\CMakeFiles\build\Boost-prefix\src\Boost as the root. How could I these so they'd be built to \depends\boost (or to that effect) and how to include the libraries to be linked to the solution? This linking is a separate problem I have, I know how to include the headers from this strange directory, but it's not really what I want.
  2. It looks like the VS IDE gives first warning the Boost headers aren't to be found (see the main program shortly) first and then starts the Boost build. Can this be avoided?
  3. How to make the Boost library disappear from the VS solution? I.e. not to make a project of it, but just a dependency on headers and libraries?
  4. Is there a built-in way to avoid downloading the Boost package if it is already on the disk? It looks like it will be retrieved in any event, and I've thought about checking the existence of the file.

The main.cpp (I suppose this is the relevant file in this case)

//The Boost headers are included just to check the linker.
#include "hello.hpp"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <iostream>
using std::cout;
using std::endl;

int main()
{
    hello helloer;
    cout << helloer.greet("World here") << endl;

    return EXIT_SUCCESS;
}

And then the CMakeLists.txt file.

cmake_minimum_required(VERSION 3.6 FATAL_ERROR)
set(CMAKE_VERBOSE_MAKEFILE ON)
project(Cmaketest)

if(POLICY CMP0042)
   cmake_policy(SET CMP0042 NEW)
endif()

if(POLICY CMP0066)
   cmake_policy(SET CMP0066 NEW)
endif()

# Default build type if none was specified.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
  message(STATUS "Setting build type to '${CMAKE_BUILD_TYPE} as none was specified.")

  # Possible values of build type for CMake GUI.
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# The path to extra modules.
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

# Setup build locations.
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()
set(CMAKE_CURRENT_BINARY_DIR    
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/build)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

include(ExternalProject)
include(ProcessorCount)
ProcessorCount(N)
if(NOT N EQUAL 0)
    set(CMAKE_BUILD_FLAGS -j${N})
endif()
# set(BOOST_VERSION 1.63.0)
# Boost related settings:    
# https://cmake.org/cmake/help/v3.6/module/FindBoost.html.
# Should one check the environment variables and flags here explicitly
# to remove the complaint about missing Boost library? Or should perhaps
# BOOST_ROOT be set? Point to what?
find_package(Boost)
if(NOT Boost_FOUND)
    # It shouldn't hurt to enable extensive diagnostics, just in case.
    # Also, a different set of files is downloaded for UNIX and WIN32
    # due to file permissions and line-feeds (Windows should handle
    # also Unix style line-feeds).
    set(Boost_DETAILED_FAILURE_MSG on)
    add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS})
    set(Boost_Bootstrap_Command)
    if(UNIX)
       set(Boost_Url     "http://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.tar.gz")
        set(Boost_Sha1 "2cecf1848a813de55e5770f324f084c568abca0a")
        set(Boost_Bootstrap_Command ./bootstrap.sh)
        set(Boost_b2_Command ./b2)
     elseif(WIN32)
        set(Boost_Url "http://sourceforge.net/projects/boost/files/boost/1.63.0/boost_1_63_0.zip")
        set(Boost_Sha1 "4364989afbe6b11f2d5e59df902c3ca4d7851824")
        set(Boost_Bootstrap_Command bootstrap.bat)
        set(Boost_b2_Command b2.exe)
    endif()
        set(Config_Libraries "chrono,filesystem,program_options,system,thread,test")
ExternalProject_Add(Boost
    TMP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/temp"
    DOWNLOAD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/downloads"
    URL "${CMAKE_CURRENT_SOURCE_DIR}/downloads/boost_1_63_0.zip"
    URL_HASH "SHA1=${Boost_Sha1}"
    BUILD_IN_SOURCE 1
    UPDATE_COMMAND ""
    PATCH_COMMAND ""
    CONFIGURE_COMMAND ${Boost_Bootstrap_Command} --without-icu --with_libraries=${Config_Libraries}
    BUILD_COMMAND  ${Boost_b2_Command}
        # --prefix="${CMAKE_CURRENT_SOURCE_DIR}/depends"
        --without-python
        --address-model=64
        --architecture=x64
        --threading=multi
        --link=static
        --variant=release
        --layout=tagged
        --build-type=complete
        -j${N}
    INSTALL_COMMAND ""
    # INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/depends"

    #As it happens, these directories are currently empty...
    # set(BOOST_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/depends/include/boost-1_63)
    # set(Boost_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/depends/boost_1_63/include)
    # set(Boost_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/depends/boost_1_63/lib)
)
endif()

 set(Boost_USE_STATIC_LIBS OFF)
 set(Boost_USE_MULTITHREADED ON)
 set(Boost_USE_STATIC_RUNTIME OFF)
 include_directories(${CMAKE_SOURCE_DIR}/src)

# Grabbing just all the test project files.
file(GLOB SOURCES "src/*.*")
add_executable(cmaketest ${SOURCES})
# TARGET_LINK_LIBRARIES(cmaketest ${Boost_LIBRARY})
2
Is your intention and goal to build Boost from sources or you just want to use Boost in your app, where your app is built using CMake? In latter case, I suggest to download prebuilt Boost e.g. from here sourceforge.net/projects/boost/files/boost-binaries/1.63.0 and then in your CMake use find_package(Boost 1.63 REQUIRED), that will set variables (see FindBoost module documentation) with location of Boost libraries and headers. In you may need to help FindBoost by providing BOOST_ROOT variable in your CMakeLists.txt from which you call find_package()ivan_onys
I would like to build it from the sources to learn to do that in the context of Boost. The next thing would be to take a binary dependency, say, from vspkg, Nuget, Conan or somesuch. I've tentatively taken a look at that too. In any event, I have this current problem I would like to solve. What @fedepad wrote was helpful to see the errors of my ways, but still some way to go. I believe I update the question a bit later (on mobile currently) to the latest attempt.Veksi
@ivan_onys I could also imagine there are issues on how to decide about including debug and release binaries depending on the build. But maybe for later time. :)Veksi
@ivan_onys I'd say the idea is to allow people who download the sources to just cmake, make and make install without worrying about tons of dependencies (especially boost, which is a hell of a dependence); that could help less technical users to be able to build and use the application.JoaoBapt

2 Answers

1
votes

I will attempt to give you some hints, to try to answer your questions.

1) With this snippet you should be able to have sources and built files in the right directories. I kept TMP_DIR "${Cmaketest_SOURCE_DIR}/temp" but in my project I don't use that line.

ExternalProject_Add(Boost
    TMP_DIR "${Cmaketest_SOURCE_DIR}/temp"
    DOWNLOAD_DIR "${Cmaketest_SOURCE_DIR}/downloads"
    URL "${Cmaketest_SOURCE_DIR}/downloads/boost_1_63_0.zip"
    URL_HASH "SHA1=${Boost_Sha1}"
    SOURCE_DIR ${Cmaketest_SOURCE_DIR}/downloads/boost_1_63_0
    BUILD_IN_SOURCE 1
    UPDATE_COMMAND ""
    PATCH_COMMAND ""
    CONFIGURE_COMMAND ${Boost_Bootstrap_Command} --without-icu --with_libraries=${Config_Libraries}
    BUILD_COMMAND  ${Boost_b2_Command}
        --prefix="${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0"
        --without-python
        --address-model=64
        --architecture=x64
        --threading=multi
        --link=static
        --variant=release
        --layout=tagged
        --build-type=complete
        -j${N}
    INSTALL_COMMAND ${Boost_b2_Command} --prefix="${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0" --without-python
        --address-model=64
        --architecture=x64
        --threading=multi
        --link=static
        --variant=release
        --layout=tagged
        --build-type=complete
        -j${N} install
    INSTALL_DIR "${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0"
)

set(BOOST_ROOT ${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0)
set(Boost_LIBRARY ${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0/lib)
set(Boost_INCLUDE_DIR ${Cmaketest_SOURCE_DIR}/depends/boost_1_63_0/include)
include_directories(${Boost_INCLUDE_DIR})

To notice that you were not calling "install" so once built in that "strange" directory, the files were not moved to the specified prefix. Notice also the use of ${Cmaketest_SOURCE_DIR} instead of the previous.
Try to print both and see if there's a difference.

2) To address the warning you get in case Boost is not found, you should write:

find_package(Boost QUIET)  

3) To address this I guess you could not generate project files, i.e. instead of having

cmake build -G "Visual Studio 14 2015 Win64"  

just have cmake . or cmake .. depending whether you will do an in-source or an out-of-source build. I suggest doing out-of-source builds, but that's your choice.
4) FindBoost.cmake (FindBoost.cmake) gives you the possibility to pass an arbitrary path to a Boost directory. You could use that at configuration to hint CMake to look for Boost in the location you give, e.g. you would call cmake in the following way:

cmake -DBOOST_ROOT=/path_to_cmaketest_dir/depends/boost_1_63_0 ..  

and if your system might be picky you could specify all things:

cmake -DBOOST_ROOT=/path_to_cmaketest_dir/depends/boost_1_63_0 -DBOOST_LIBRARYDIR=/path_to_cmaketest_dir/depends/boost_1_63_0/lib DBOOST_INCLUDEDIR=/path_to_cmaketest_dir/depends/boost_1_63_0/include ..  

Notice that in the last two snippets I assumed configuration of an out-of-source build.
Also notice that if you already installed or have the Boost package downloaded, using ${Cmaketest_SOURCE_DIR} in the snipped of code in 1) should solve also 4) so when it will not find Boost it will try to download but it will not, since now cmake should be able to see the file (.zip).

0
votes

Please see CMaker_Boost, build the Boost with the CMake at a configure time. Now it is tested on the Linux and Android, gcc and clang. Other systems are not tested. I hope this helps.