0

I have a project that depends on Intel's oneTBB. My project is structured as follows:

external/
    | - CMakeLists.txt
    | - oneTBB/  (this is a git submodule)
    | - ...
include/
lib/
include/
CMakeLists.txt

I currently get things to compile by manually building oneTBB and installing it inside a prefix directory located at external/oneTBB/prefix by running the following (bash) commands:

cd oneTBB
mkdir -p prefix
mkdir -p build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../prefix -DTBB_TEST=OFF ..
cmake --build .
cmake --install .

I then simply include and link using this prefix. (I got this from following the oneTBB READMEs)

While this works without issue, I'm currently trying to clean up my CMake such that its easier to build on Windows as well. Ideally, I'm looking to get to a point where I can simply run:

mkdir build
cd build
cmake ..
cmake --build .

and my project will build itself and all dependencies.

I got this working with other dependencies such as glfw and eigen by simply adding (to the CMakeLists.txt in external/:

add_subdirectory(glfw)
add_subdirectory(eigen)

But adding add_subdirectory(oneTBB) throws a LOT of warnings, starting with:

CMake Warning at external/oneTBB/CMakeLists.txt:116 (message):
  You are building oneTBB as a static library.  This is highly discouraged
  and such configuration is not supported.  Consider building a dynamic
  library to avoid unforeseen issues.

-- TBBBind build targets are disabled due to unsupported environment
-- Configuring done
CMake Warning (dev) at external/oneTBB/src/tbb/CMakeLists.txt:15 (add_library):
  Policy CMP0069 is not set: INTERPROCEDURAL_OPTIMIZATION is enforced when
  enabled.  Run "cmake --help-policy CMP0069" for policy details.  Use the
  cmake_policy command to set the policy and suppress this warning.

  INTERPROCEDURAL_OPTIMIZATION property will be ignored for target 'tbb'.
This warning is for project developers.  Use -Wno-dev to suppress it.

I have no need to build oneTBB as a static library. Am I doing something wrong in my attempt? Really all I need is for oneTBB to be built as a dynamic library and placed somewhere I can link it to (without installing it on the system overall)


Similar question:

I am also including the METIS library which depends on GKlib. Currently I'm doing this in a similar way to what I did for oneTBB where I manually build each using the following script:

# Setup the GKlib library:
cd GKlib
mkdir -p prefix
mkdir -p build
cd build
cmake -DCMAKE_INSTALL_PREFIX=../prefix ..
cmake --build . -j
cmake --install .
cd ../../

# Setup the METIS library:
cd METIS
mkdir -p prefix
make config prefix=../prefix gklib_path=../GKlib/prefix #(GKLib path is done from root, install path done relative to build)
make install -j
cd ../

When I try to add them using:

add_subdirectory(GKlib)
add_subdirectory(METIS)

it throws errors that METIS cannot find GKlib:

CMake Error at external/METIS/CMakeLists.txt:50 (add_subdirectory):
  add_subdirectory given source "build/xinclude" which is not an existing
  directory.

While I recognize this is a separate issue, I figured to include it here as it is related to my issues with add_subdirectory()

starball
  • 20,030
  • 7
  • 43
  • 238
Chris Gnam
  • 311
  • 2
  • 7
  • 2
    Stick to one question per question post. Move your "similar question" to a different question post, or make it clear how it is similar, because I can't see how they are similar. Different diagnostic messages and different problems. – starball Feb 05 '23 at 21:23

2 Answers2

1

Many projects expect that you invoke CMake on them separately instead of adding them into an existing project with add_subdirectory. While there might be a way to make add_subdirectory work with oneTBB, there is an easier way.

CMake has a function that allows you to download, build, and install external projects at build time: ExternalProject_Add.

Here's an example for spdlog, taken straight from one of my own projects:

# project_root/thirdparty/spdlog/CMakeLists.txt

string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER)

ExternalProject_Add(spdlog-project
        GIT_REPOSITORY https://github.com/gabime/spdlog
        GIT_TAG edc51df1bdad8667b628999394a1e7c4dc6f3658
        GIT_SUBMODULES_RECURSE ON
        GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
        INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/install"
        LIST_SEPARATOR |
        CMAKE_CACHE_ARGS
        "-DCMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
        "-DCMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
        "-DCMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
        "-DCMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}:STRING=${CMAKE_SHARED_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}"
        "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
        "-DCMAKE_INSTALL_PREFIX:STRING=<INSTALL_DIR>"
        "-DSPDLOG_BUILD_EXAMPLE:BOOL=OFF"
        )

add_library(ext-spdlog INTERFACE)
add_dependencies(ext-spdlog spdlog-project)
ExternalProject_Get_property(spdlog-project INSTALL_DIR)
target_include_directories(ext-spdlog SYSTEM INTERFACE "${INSTALL_DIR}/include")
target_link_directories(ext-spdlog INTERFACE "${INSTALL_DIR}/lib")
target_link_libraries(ext-spdlog INTERFACE spdlog$<$<CONFIG:Debug>:d>)

After that, my project simply links against the created library target:

target_link_libraries(my_project ext-spdlog)

To adapt this for oneTBB, you have to switch out the repository URL and commit hash, and add your own CMake definitions (i.e. "-DTBB_TEST=OFF"). Depending on how oneTBB has its include and library directories set up, you may also have to change the target_include_directories and/or target_link_directories lines. I haven't looked this up yet, but I'm sure you can figure it out.

This works regardless of whether the external project is built as a static or shared library. You shouldn't use git submodules, though - instead, let CMake do the downloading. (It'll only download and build once; subsequent builds will not re-build the external project if it's already built and up-to-date.)

Jonathan S.
  • 1,796
  • 5
  • 14
  • @user The question states: "Ideally, I'm looking to get to a point where I can simply run: (Single CMake build command) and my project will build itself and all dependencies." This answer shows a clean way to get to that goal (with ExternalProject) - so it directly answer's the original (first) question. It doesn't answer the second "similar question", but as you've already said, that one should be its own separate question on the site. – Jonathan S. Feb 05 '23 at 21:49
  • @user Well, the user didn't say that they wanted to specifically solve the problem with `add_subdirectory`, but rather that they want to solve the problem *somehow* and they tried `add_subdirectory`, which did not work out for them. I figured that I'd show them the "official" way to fetch and build CMake-based dependencies in a CMake project, which will solve the original problem, regardless of the failed attempt that the user has already made at solving it. I expect the user to be able to adapt my example to their particular problem. – Jonathan S. Feb 05 '23 at 22:15
  • This is actually a perfect solution as this actually *does* address the second issue. And this is an easy drop in replacement with my submodule setup as well (as you can invoke `ExternalProject_Add()` with a path to a source directory instead. I've gotten a setup loosely based off of how you presented it here working with several of my dependencies now. I'm trying to work through the rest at which time I'd select this as the correct solution and update my post with my specific fix – Chris Gnam Feb 05 '23 at 23:35
0

I have no need to build oneTBB as a static library. Am I doing something wrong in my attempt? Really all I need is for oneTBB to be built as a dynamic library and placed somewhere I can link it to (without installing it on the system overall)

All your diagnostic messages indicate that it's actually being configured to be built as a static library, and additional clues point to the probability that you've set BUILD_SHARED_LIBS to false in the scope where you add_subdirectory(oneTBB).

CMake Warning at external/oneTBB/CMakeLists.txt:116 (message):
  You are building oneTBB as a static library.  This is highly discouraged
  and such configuration is not supported.  Consider building a dynamic
  library to avoid unforeseen issues.

If you look in oneTBB's CMakeLists.txt file, you'll the following:

if (NOT DEFINED BUILD_SHARED_LIBS)
    set(BUILD_SHARED_LIBS ON)
endif()

if (NOT BUILD_SHARED_LIBS)
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
    message(WARNING "You are building oneTBB as a static library. This is highly discouraged and such configuration is not supported. Consider building a dynamic library to avoid unforeseen issues.")
endif()

And then right after that, you get

-- TBBBind build targets are disabled due to unsupported environment

The corresponding section of oneTBB's CMakeLists.txt file is:

if (TBB_FIND_PACKAGE OR TBB_DIR)
    ...
else()
    if (APPLE OR NOT BUILD_SHARED_LIBS)
        message(STATUS "TBBBind build targets are disabled due to unsupported environment")
    else()
        add_subdirectory(src/tbbbind)
    endif()
    ...

Both of these clues indicate that in the variable scope at which you add_subdirectory(oneTBB), BUILD_SHARED_LIBS is set to a falsy value.

Set BUILD_SHARED_LIBS it to a truthy value (Ex. 1, TRUE, YES, ON, etc.) before doing add_subdirectory(oneTBB) and then restore the previous value afterward.

Ex.

set(BUILD_SHARED_LIBS_TEMP "${BUILD_SHARED_LIBS}")
set(BUILD_SHARED_LIBS YES)
add_subdirectory(oneTBB)
set(BUILD_SHARED_LIBS "${BUILD_SHARED_LIBS_TEMP}")
unset(BUILD_SHARED_LIBS_TEMP)
starball
  • 20,030
  • 7
  • 43
  • 238