Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake and Make need to be run twice in order to build code successfully

I am using CMake 3.8.2, GNU make 4.2.1 and GCC 6.4.0 for my C++14 project and I noticed a strange behavior when building. I am using CMake for an out-of-source build in a sub-folder called "build" where I run cmake .. followed by make.

CMake runs fine without any errors and make will build all source files like I expect until it is done compiling and starts linking them. It will then fail with an error

[ 83%] ...
[100%] Linking CXX executable myproject
/usr/bin/ld: some-source-file.cc.o: undefined reference to symbol '_ZNKSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEE3strEv@@GLIBCXX_3.4.21'

Interestingly it doesn't show any compiler warnings up to this point and only shows the above mentioned linker error.

Now when I ignore the error and simply run cmake .. and then make again (just like I did before) I get all the compiler warnings that my code should produce and everything links perfectly fine, even though I didn't change any code or CMake-related files in the meantime.

I can reproduce this behavior by deleting all files in the build dir by running rm -r *.

Here is my CMakeLists.txt file:

# Define minimum required CMake version
cmake_minimum_required(VERSION 3.8.2)

# Setting compiler related settings
set(CMAKE_CXX_COMPILER "${CMAKE_SOURCE_DIR}/toolchain/binary/gcc-6.4.0/bin/gcc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wconversion -O2 -lstdc++")
set(CMAKE_CXX_STANDARD 14)

# Define project name
project(MyProject)

# Find source files
file(GLOB_RECURSE SOURCES application/*.cc)

# Adding third-party sources
set(SOURCES ${SOURCES} "third-party/cpp-base64/base64.cpp")

# Executable to be built from which source files
add_executable(myproject ${SOURCES})

# Find and include and link Botan
find_library(BOTAN botan-2 "third-party/botan/build/lib")
include_directories("third-party/botan/build/include/botan-2")

# Includes that are part of the project
include_directories("${CMAKE_SOURCE_DIR}/application/include")

# Include nlohmann/json
include_directories("third-party/json/src")

# Include cpp-base64 by René Nyffenegger
include_directories("third-party/cpp-base64")

find_package(Boost REQUIRED COMPONENTS program_options)
if(Boost_FOUND)
  include_directories(${Boost_INCLUDE_DIRS})
endif()

# Link third-party libraries
target_link_libraries(myproject ${Boost_LIBRARIES} ${BOTAN})

Note: I am required to check-in the compiler and libraries I am using, which is why I specified them in the CMake file.

like image 985
comfreak Avatar asked Dec 06 '17 22:12

comfreak


People also ask

Do I need to rerun CMake?

The answer is simple: The cmake binary of course needs to re-run each time you make changes to any build setting, but you wont need to do it by design; hence "never" is correct regarding commands you have to issue.

How do I build and run with CMake?

To build with just cmake change directory into where you want the binaries to be placed. For an in-place build you then run cmake and it will produce a CMakeCache. txt file that contains build options that you can adjust using any text editor.

When should I run CMake or make?

CMake is much more high-level. It's tailored to compile C++, for which you write much less build code, but can be also used for general purpose build. make has some built-in C/C++ rules as well, but they are useless at best.


1 Answers

If it only works the second time it has to do with cached variables.

So I'm pretty sure that it will work the first time if you modify CMAKE_CXX_COMPILER setting by adding set(... CACHE INTERNAL "") to:

set(CMAKE_CXX_COMPILER "${CMAKE_SOURCE_DIR}/toolchain/binary/gcc-6.4.0/bin/gcc" CACHE INTERNAL "")

And move set(CMAKE_CXX_FLAGS ...) after the project() command.

But please also be noted that you shouldn't put the compiler into your CMakeLists.txt.

References

  • CMake: In which Order are Files parsed (Cache, Toolchain, …)?
  • Passing compiler options cmake
  • CMake Error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found
like image 157
Florian Avatar answered Sep 30 '22 07:09

Florian