I made simple kernel for studying purposes. I cange MakeFile to CMakeLists.txt to automatically genreate my kernel form sources. But I encounter this relocation error.
/usr/bin/ld: CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/multiboot2_boot32.asm.o: relocation R_X86_64_32 against `.boot.32' can not be used when making a PIE object; recompile with -fPIE
To solve this I think I have to remove -fno-pie in linker flags. By checking log of gcc with make VERBOSE=1, I can found that there is CMAKE_CXX_FLAGS at my linker flags.
[100%] Linking CXX executable x86_64-kernel.bin
/usr/bin/cmake -E cmake_link_script CMakeFiles/x86_64-kernel.bin.dir/link.txt --verbose=1
/usr/bin/gcc -mno-red-zone -mcmodel=large -mno-sse -ffreestanding -nostdlib -fno-pie -fno-pic -rdynamic -n -T /home/ahn9807/study/AOS/src/arch/x86_64/linker.ld CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/kernel_entry.cpp.o CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/multiboot2_boot32.asm.o CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/multiboot2_boot64.asm.o CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/multiboot2_header.asm.o -o x86_64-kernel.bin
/usr/bin/ld: CMakeFiles/x86_64-kernel.bin.dir/src/arch/x86_64/multiboot2_boot32.asm.o: relocation R_X86_64_32 against `.boot.32' can not be used when making a PIE object; recompile with -fPIE
How can I remove this CMAKE_CXX_FLAGS in my LINKER_FLAGS? Why camke automatically insert this useless options for my MakeFile? Is there any other way to bypass this error messages? I hope your answers...
And this is my CMakeLists.txt.
cmake_minimum_required(VERSION 2.17)
project(kernell)
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 1)
set(CMAKE_CXX_STANDAED 17)
set(KERNEL_BIN "x86_64-kernel.bin")
set(CMAKE_BINARY_DIR ${PROJECT_SOURCE_DIR}/build)
set(LINKER_SCRIPT ${PROJECT_SOURCE_DIR}/src/arch/x86_64/linker.ld)
set(GRUB_CFG ${PROJECT_SOURCE_DIR}/src/arch/x86_64/grub.cfg)
set(CMAKE_ASM_NASM_OBJECT_FORMAT "elf64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mno-red-zone -mcmodel=large -mno-sse -ffreestanding -nostdlib -fno-pie -fno-pic")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mno-red-zone -mcmodel=large -mno-sse -ffreestanding -nostdlib -fno-pie -fno-pic")
set(CMAKE_ASM_FLAGS "{CMAKE_ASM_FLAGS} -felf64")
set(CMAKE_CXX_COMPILER "/usr/bin/gcc")
set(CMAKE_C_COMPILER "/usr/bin/g++")
set(CMAKE_LINKER "/usr/bin/ld")
enable_language(ASM_NASM)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include/
)
add_executable(
${KERNEL_BIN}
# Header files
include/arch/x86_64/kernel_entry.h
include/arch/x86_64/vga_text.h
include/arch/x86_64/multiboot2.h
# Source files
src/arch/x86_64/kernel_entry.cpp
src/arch/x86_64/multiboot2_boot32.asm
src/arch/x86_64/multiboot2_boot64.asm
src/arch/x86_64/multiboot2_header.asm
)
set_target_properties(${KERNEL_BIN} PROPERTIES LINK_FLAGS "-n -T ${LINKER_SCRIPT}")
add_custom_command(TARGET ${KERNEL_BIN} POST_BUILD
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/build/isofiles/boot/grub
COMMAND cp ${KERNEL_BIN} ${CMAKE_BINARY_DIR}/build/isofiles/boot/${KERNEL_BIN}
COMMAND cp ${GRUB_CFG} ${CMAKE_BINARY_DIR}/build/isofiles/boot/grub
COMMAND grub-mkrescue -o kernel.iso ${CMAKE_BINARY_DIR}/build/isofiles
COMMAND rm -r ${CMAKE_BINARY_DIR}/build/
)
Finally I figure out how to remove useless linker argument from cmake. CMAKE uses compiler as an default linker. In my case, gcc is default linker because I build my source code with gcc. The important fact is that cmake also berings CMAKE_CXX_FLAGS with gcc in linking stage. So we have to use custom linker as like this to avoid cmake linking our oject files with default compiler linker.
set(CMAKE_LINKER "/usr/bin/ld")
set(CMAKE_LINKER_FLAGS "-n -T ${LINKER_SCRIPT}")
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> ${CMAKE_LINKER_FLAGS} <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
In this way, we can automatically generate executable with custom linker.
Related
I tried to use -rdynamic option in my CMakeLists.txt file, like this:
cmake_minimum_required(VERSION 3.5)
project(Tmuduo CXX)
...
set(CMAKE_CXX_STANDARD 11)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options(-Wthread-safety )
endif()
add_compile_options(
# -DVALGRIND
-Wall
-Wno-unused-parameter
-Woverloaded-virtual
-Wpointer-arith
-Wwrite-strings
-O3
-rdynamic
)
...
When I use cmake .. -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang and make VERBOSE=1, I got some message as follow:
Just as you can see, the -rdynamic compile option did appear in the clang++ command and the compiler also complainted that the argument was unused. But when I used the command below, something strange happended.
clang++ -I/home/phoenix/MyProject/Tmuduo -g -Wthread-safety -Wall -Wno-unused-parameter -Woverloaded-virtual -Wpointer-arith -Wwrite-strings -rdynamic -std=gnu++11 test/Exception_test.cc base/Exception.cc base/CurrentThread.cc -o exception_test -O3
Everything goes well. This time, the -rdynamic option works. That reall make me confuse. Can anyone tell me what's going on here? Why the clang++ command works while the cmake failed?
Because -rdynamic is a linker option, so if you use when compiling a source file into an object *.o it does nothing, there is no link phase here.
When linking all the *.o and libraries into the finally executable, then it is actually used.
From man gcc (but clang uses the same):
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it.
This instructs the linker to add all symbols, not only used ones, to the
dynamic symbol table. This option is needed for some uses of "dlopen" or to
allow obtaining backtraces from within a program.
I want to transfer an old side project to CMake. Previously it used a Makefile with custom variables, defines and etc. I specified the same flags to compile various configurations. I did it this way:
cmake_minimum_required(VERSION 3.2.2)
project(wise_RK)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SOURCES main.cpp devices/RK.cpp LogWriter/LogWriter.cpp)
set(CMAKE_CXX_FLAGS "-DIMA -std=c++11 -Wall -Wextra -c -O2 -MMD -MP -MF '$#.d'")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(
structs
devices
LogWriter
/home/data/lib/wise_versioning
/home/data/lib/wisenet
/home/data/lib/wise_log
/home/data/lib/wise_rs_device
/home/data/lib/json
)
# wise_rs_device
add_library(wise_rs_device STATIC IMPORTED GLOBAL)
set_target_properties(wise_rs_device PROPERTIES
IMPORTED_LOCATION "/home/data/lib/wise_rs_device/libwise_rs_device.a"
INTERFACE_INCLUDE_DIRECTORIES "/home/data/lib/wise_rs_device/"
)
# wisenet
add_library(wisenet STATIC IMPORTED GLOBAL)
set_target_properties(wisenet PROPERTIES
IMPORTED_LOCATION "/home/data/lib/wisenet/libwise_net_rs485.so"
INTERFACE_INCLUDE_DIRECTORIES "/home/data/lib/wisenet/"
)
#wise_log
add_library(wise_log STATIC IMPORTED GLOBAL)
set_target_properties(wise_log PROPERTIES
IMPORTED_LOCATION "/home/data/lib/wise_log/Release/GNU-Linux/libwise_log.so"
INTERFACE_INCLUDE_DIRECTORIES "/home/data/lib/wise_log/"
)
add_executable(wise_rk ${SOURCES})
target_link_libraries(wise_rk PRIVATE wise_rs_device wisenet wise_log)
add_definitions(-DSOME_IMPORTANT_DEFINITION)
-D is define of various configurations.
In the Makefile, the list of project object files (not libraries) involved in the assembly was like this:
OBJECTS:=$(shell find * -type f -name "*.cpp" | sed "s/\.cpp/\.o /" | sort)
DEPENDS:=$(addprefix build/$(CONF)/, ${OBJECTS:.o=.o.d})
-include ${DEPENDS}
When I built my CMake:
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/wise_rk.dir/link.txt --verbose=1
/usr/bin/c++ -DIMA -std=c++11 -Wall -Wextra -c -O2 -MMD -MP -MF '$#.d' CMakeFiles/wise_rk.dir/main.cpp.o CMakeFiles/wise_rk.dir/devices/RK.cpp.o CMakeFiles/wise_rk.dir/LogWriter/LogWriter.cpp.o -o wise_rk -rdynamic /home/data/lib/wise_rs_device/libwise_rs_device.a /home/data/lib/wisenet/libwise_net_rs485.so /home/data/lib/wise_log/Release/GNU-Linux/libwise_log.so
c++: warning: CMakeFiles/wise_rk.dir/main.cpp.o: linker input file unused because linking not done
c++: warning: CMakeFiles/wise_rk.dir/devices/RK.cpp.o: linker input file unused because linking not done
c++: warning: CMakeFiles/wise_rk.dir/LogWriter/LogWriter.cpp.o: linker input file unused because linking not done
c++: warning: /home/data/lib/wise_rs_device/libwise_rs_device.a: linker input file unused because linking not done
c++: warning: /home/data/lib/wisenet/libwise_net_rs485.so: linker input file unused because linking not done
c++: warning: /home/data/lib/wise_log/Release/GNU-Linux/libwise_log.so: linker input file unused because linking not done
make[2]: Leaving directory `/home/anzipex/Downloads/wise_RK/build'
/usr/local/bin/cmake -E cmake_progress_report /home/anzipex/Downloads/wise_RK/build/CMakeFiles 1 2 3
[100%] Built target wise_rk
make[1]: Leaving directory `/home/anzipex/Downloads/wise_RK/build'
/usr/local/bin/cmake -E cmake_progress_start /home/anzipex/Downloads/wise_RK/build/CMakeFiles 0
I do not know what to do next to solve this kind of problem.
I changed all the .so libs to SHARED. And also removed part of flags -c -O2 -MMD -MP -MF '$#.d' like #Botje wrote. Seems like project built.
Passing --coverage to gcc while also linking LLVM causes an undefined reference to `__gcov_exit' error from the linker. I've set up a fresh project to try to isolate this problem. You can view the source on github and inspect the compiler output on Travis-CI.
This is the difference between a coverage and a non-coverage build
-DCMAKE_CXX_FLAGS="--coverage"
This is the difference between an LLVM and a non-LLVM build
target_link_libraries(Test
PUBLIC
LLVMCore
)
The LLVM job succeeds. The Coverage job succeeds. The LLVM + Coverage job fails with this error
undefined reference to `__gcov_exit'
Notes:
Check [CMake 3.13]: CMAKE_<LANG>_FLAGS for details regarding which env var affects which cmake var - as you figured out in your (deleted) answer
Only noticed cxx_std_17 from CMake 3.8, so you might want to update your cmake_minimum_required
Forked your repo to [GitHub]: CristiFati/gcov_error - An attempt to reproduce the gcov/llvm linker error and did some debugging on it
Beware, I might delete it someday
Was able to get my head around Travis CI, it's a real gold-mine
At the beginning I thought that it would be a trivial fix (something related to -fprofile-arcs, -ftest-coverage, -lgcov flags) as noted in [Man7]: GCC(1) (--coverage option), but it wasn't.
I wasn't able to reproduce the problem on my Ubuntu 16 pc064 VM (although Travis is very nice, it's kind of slow for debugging purposes (especially when due to rushing one might forget or add an extra character when editing :) ) and also it doesn't offer the same access level that a local machine does,) because the environment:
CMake 3.5.1
GCC 5.4.0
LLVM 3.8.0
is pretty far away from what's on the Travis Docker image. I must mention that neither I tried building the packages from sources (that would probably have caused lots of headaches), nor did I try downloading them from the repositories where they are downloaded during CI builds (didn't even check if those repos are public). Anyway the VM was pretty much unusable because:
I couldn't reproduce the issue (after some minor changes to adapt to older tools), everything worked
More: I ran into [SO]: Error when using CMake with LLVM (#CristiFati's answer)
It was eating me alive, so I ended up building 48 freaking times (on Travis) in order to get it working, and that is only because I failed to notice the obvious.
The problem
For each of the 3 configurations I'm going to paste the compile and link (G++) commands generated (from your build: [Travis CI]: Kerndog73/gcov_error - Build #24)
LLVM:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
Coverage:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test
LLVM + Coverage:
/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp
/usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
After lots of ghosts chasing, I noticed -L/usr/lib/gcc/x86_64-linux-gnu/4.8 being passed to the linker when LLVM is included. GCC 4.8 is installed on the Docker, so apparently GCC 7.4 was used for compilation, and GCC 4.8 for linking, which is Undefined Behavior.
I'm also pasting the Collect command (closer to the linker) from a slight variation (with -v) of #3. (all the libraries specified with -l* and without the full path (e.g. -lgcov, -lgcc_s, -lgcc) have the wrong version because will be picked up from the wrong directory):
/usr/lib/gcc/x86_64-linux-gnu/7/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper -plugin-opt=-fresolution=/tmp/ccyDh97q.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -export-dynamic -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o Test /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/7 -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. CMakeFiles/Test.dir/main.cpp.o /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread /usr/lib/llvm-7/lib/libLLVMDemangle.a -lstdc++ -lm -lgcov -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.0
Some test commands placed in .travis.yml's after_script section, yielded the following output:
$ _GCOV_LIB7=/usr/lib/gcc/x86_64-linux-gnu/7/libgcov.a
$ (nm -S ${_GCOV_LIB7} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB7}
0000000000001e40 000000000000008b T __gcov_exit
$ _GCOV_LIB48=/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a
$ (nm -S ${_GCOV_LIB48} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB48}
/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a
So, LibGCC (libgcov.a) was modified somewhere between the 2 involved versions (__gcov_exit symbol was added), and G++ knew it has one but Ld didn't provide it (because of the wrong lib) hence the error.
Now, why does LLVM add this library search path, I don't know (probably because it was built with GCC 4.8 - or smth close to it), but here's what I can think of:
LLVM is not meant to be used with GCC 7 (although I didn't find any such restriction while quickly browsing [LLVM]: Getting Started with the LLVM System)
A bug in LLVM (considering the other issue that I ran into, I tend to think this is the winner)
I found ways for both of them:
Use an older G++ (v4.8 - installed by default on the Docker)
export CXX=g++ (might even not be necessary)
G++ (not CMake this time) doesn't know about cxx_std_17, so the easiest way is to remove the afferent target_compile_features (the drawback is that code won't be C++17 "compliant")
Since I don't know how to "undo" passing the (faulty) library search path, the workaround that I came up with is to specify the correct one before it.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(gcov_test)
find_package(LLVM 7.0.0 REQUIRED CONFIG)
message(STATUS "Found LLVM: ${LLVM_DIR} ${LLVM_PACKAGE_VERSION}")
add_executable(Test
"main.cpp"
)
target_compile_features(Test
PUBLIC cxx_std_17
)
target_include_directories(Test
PUBLIC ${LLVM_INCLUDE_DIRS}
)
target_compile_definitions(Test
PUBLIC ${LLVM_DEFINITIONS}
)
if(LINK_WITH_LLVM)
# #TODO - cfati: Everything in this block is to avoid hardcoding default libgcc path (/usr/lib/gcc/x86_64-linux-gnu/7)
set(_COLLECT_LTO_WRAPPER_TEXT "COLLECT_LTO_WRAPPER=")
execute_process(
COMMAND bash -c "$0 -v 2>&1 | grep ${_COLLECT_LTO_WRAPPER_TEXT} | sed s/${_COLLECT_LTO_WRAPPER_TEXT}//" "${CMAKE_CXX_COMPILER}"
OUTPUT_VARIABLE _GAINARIE_COLLECT_TMP_VAR
)
get_filename_component(_GAINARIE_GCC_DEFAULT_PATH ${_GAINARIE_COLLECT_TMP_VAR} DIRECTORY)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${_GAINARIE_GCC_DEFAULT_PATH}")
#set (GCCOPT "${GCCOPT} -L${_GAINARIE_GCC_DEFAULT_PATH}")
# #TODO END
target_link_libraries(Test
PUBLIC LLVMCore
)
endif()
Note: I tried to come up with something more elegant (I'm sure that it is), but I couldn't (tried using CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES, target_link_libraries, link_directories and a few more) at this point.
I am currently trying to link Bonmin using cmake in my project under macOS High Sierra (10.13.4) with Xcode version 9.3. Before I describe the setup I should mention that the Bonmin example (/PATH_TO_BONMIN/Bonmin/examples/CppExample) compiles with the included make files. Later example I try to get to work in my environment, but it is not working. Thus, I think there must be an incompatibility.
Bonmin 1.8 (https://www.coin-or.org/Tarballs/Bonmin/) was build on my Mac using
../configure -C --disable-shared F77="/usr/local/bin/gfortran" FFLAGS="-fexceptions -m64 -fbackslash" CFLAGS="-fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64" CXXFLAGS="-fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64"
My FindBonmin.cmake uses the package configuration files from "${BONMIN_LIBRARY_DIR}/pkgconfig":
find_path(BONMIN_LIBRARY_DIR
NAMES libbonmin.a
HINTS ...
HINTS /usr/local/include/coin
HINTS ${BONMIN_ROOT_DIR}/include/coin
HINTS ${BONMIN_ROOT_DIR}/include
)
if(IS_DIRECTORY "${BONMIN_LIBRARY_DIR}/pkgconfig")
set(CMAKE_PREFIX_PATH "${BONMIN_LIBRARY_DIR}/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "${BONMIN_LIBRARY_DIR}/pkgconfig")
else()
message("Directory ${BONMIN_LIBRARY_DIR}/pkgconfig does not exist!")
endif()
From this I get the following:
${BONMIN_LIBRARY_DIR}/pkgconfig =
/Users/<PATH>/Bonmin-1.8/build/lib/pkgconfig
${PKG_BONMIN_INCLUDE_DIRS} =
/Users/<PATH>/Bonmin-1.8/build/include/coin;/Users/<PATH>/Bonmin-1.8/build/include/coin/ThirdParty;/Users/<PATH>/Bonmin-1.8/build/include/coin;/Users/<PATH>/Bonmin-1.8/build/include/coin/ThirdParty
${PKG_BONMIN_LDFLAGS} = -L/Users/<PATH>/Bonmin-1.8/build/lib;-L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/x86_64;-L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/../../../x86_64;-L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3;-L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/../../..;-lbonmin;-lCbcSolver;-lCbc;-lCgl;-lOsiClp;-lClpSolver;-lClp;-lcoinasl;-lm;-ldl;-lOsi;-lCoinUtils;-lbz2;-lz;-framework;Accelerate;-lm;-lipopt;-framework;Accelerate;-lm;-ldl;-lcoinmumps;-framework;Accelerate;-lgfortranbegin;-lgfortran;-lSystem
This is used for the example:
include_directories(${PKG_BONMIN_INCLUDE_DIRS} )
add_executable(bonminExample runnables/bonminExample.cpp)
target_link_libraries(bonminExample ${PKG_BONMIN_LDFLAGS})
Additional information:
cmake_minimum_required(VERSION 3.6)
project(MyProject CXX)
# The version number.
set (MyProject_VERSION_MAJOR 1)
set (MyProject_VERSION_MINOR 0)
set(CMAKE_C_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang" CACHE FILEPATH "Path to the used C compiler; default clang." FORCE)
set(CMAKE_CXX_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang++" CACHE FILEPATH "Path to the used C++ compiler; default clang++." FORCE)
set(OPENMP_LIBRARIES "/usr/local/Cellar/llvm/5.0.1/lib" CACHE FILEPATH "Path to the OpenMP libraries." FORCE)
set(OPENMP_INCLUDES "/usr/local/Cellar/llvm/5.0.1/include" CACHE FILEPATH "Path to the OpenMP includes." FORCE)
## Set c++14
set(CMAKE_CXX_STANDARD 14)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif()
...
The error message I get, while trying to link Bonmin is:
ld: framework not found -lAccelerate
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [/Users/<PATH>/myproject/bin/bonminExample] Error 1
make[1]: *** [src/CMakeFiles/bonminExample.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
With the details:
[ 3%] Linking CXX executable /Users/<PATH>/myproject/bin/bonminExample
cd /Users/<PATH>/build_debug/src && /opt/local/bin/cmake -E cmake_link_script CMakeFiles/bonminExample.dir/link.txt --verbose=1
cd /Users/<PATH>/build_debug && /opt/local/bin/cmake -E cmake_depends "Unix Makefiles" /Users/<PATH>/myproject /Users/<PATH>/build_debug/googletest-src/googlemock /Users/<PATH>/build_debug /Users/<PATH>/build_debug/googletest-build/googlemock /Users/<PATH>/build_debug/googletest-build/googlemock/CMakeFiles/gmock_autogen.dir/DependInfo.cmake --color=
cd /Users/<PATH>/build_debug && /opt/local/bin/cmake -E cmake_depends "Unix Makefiles" /Users/<PATH>/myproject/ /Users/<PATH>/myproject/src /Users/<PATH>/build_debug /Users/<PATH>/build_debug/src /Users/<PATH>/build_debug/src/CMakeFiles/PGT.dir/DependInfo.cmake --color=
/usr/local/Cellar/llvm/5.0.1/bin/clang++ -fopenmp=libomp -Wno-unused-command-line-argument -DCOIN_USE_MUMPS_MPI_H -fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64 -DBONMIN_BUILD -march=native -g -Wall -ggdb -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/bonminExample.dir/runnables/BonminExample.cpp.o CMakeFiles/bonminExample.dir/bonminExample_autogen/mocs_compilation.cpp.o -o /Users/<PATH>/myproject/bin/bonminExample -L/usr/local/Cellar/llvm/5.0.1/lib -L/Users/<PATH>/external_libraries/ogdf20170723 -Wl,-rpath,/usr/local/Cellar/llvm/5.0.1/lib -Wl,-rpath,/Users/<PATH>/external_libraries/ogdf20170723 -L/Users/<PATH>/external_libraries/Bonming-1.8/build/lib -L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/x86_64 -L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/../../../x86_64 -L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3 -L/usr/local/lib/gcc/i686-apple-darwin8/4.2.3/../../.. -lbonmin -lCbcSolver -lCbc -lCgl -lOsiClp -lClpSolver -lClp -lcoinasl -lm -ldl -lOsi -lCoinUtils -lbz2 -lz -framework -lAccelerate -lm -lipopt -framework -lAccelerate -lm -ldl -lcoinmumps -framework -lAccelerate -lgfortranbegin -lgfortran -lSystem -lm -ldl -lOsi -lCoinUtils -lbz2 -lz -lipopt -lcoinmumps -lgfortranbegin -lgfortran -lSystem
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f googletest-build/googlemock/CMakeFiles/gmock_autogen.dir/build.make googletest-build/googlemock/CMakeFiles/gmock_autogen.dir/build
[ 4%] Automatic MOC for target gmock
cd /Users/<PATH>/build_debug/googletest-build/googlemock && /opt/local/bin/cmake -E cmake_autogen /Users/<PATH>/build_debug/googletest-build/googlemock/CMakeFiles/gmock_autogen.dir Debug
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f src/CMakeFiles/PGT.dir/build.make src/CMakeFiles/PGT.dir/build
ld: framework not found -lAccelerate
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [/Users/<PATH>/myproject/bin/bonminExample] Error 1
make[1]: *** [src/CMakeFiles/bonminExample.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f src/CMakeFiles/PGTIP.dir/build.make src/CMakeFiles/PGTIP.dir/build
Does anybody know what might be an issue or even has a solution to it?
Note that the make file from the Bonmin example gives me the following:
MBP:CppExample myname$ make VERBOSE=1
clang++ -fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64 -DBONMIN_BUILD `PKG_CONFIG_PATH=/Users/<PATH>/Bonmin-1.8/build/lib64/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/lib/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/share/pkgconfig:/opt/X11/lib/pkgconfig pkg-config --cflags bonmin` -c -o MyBonmin.o `test -f '../../../../Bonmin/examples/CppExample/MyBonmin.cpp' || echo '../../../../Bonmin/examples/CppExample/'`../../../../Bonmin/examples/CppExample/MyBonmin.cpp
clang++ -fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64 -DBONMIN_BUILD `PKG_CONFIG_PATH=/Users/<PATH>/Bonmin-1.8/build/lib64/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/lib/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/share/pkgconfig:/opt/X11/lib/pkgconfig pkg-config --cflags bonmin` -c -o MyTMINLP.o `test -f '../../../../Bonmin/examples/CppExample/MyTMINLP.cpp' || echo '../../../../Bonmin/examples/CppExample/'`../../../../Bonmin/examples/CppExample/MyTMINLP.cpp
bla=;\
for file in MyBonmin.o MyTMINLP.o; do bla="$bla `echo $file`"; done; \
clang++ -fno-common -no-cpp-precomp -fexceptions -arch x86_64 -m64 -DBONMIN_BUILD -o CppExample $bla `PKG_CONFIG_PATH=/Users/<PATH>/Bonmin-1.8/build/lib64/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/lib/pkgconfig:/Users/<PATH>/Bonmin-1.8/build/share/pkgconfig:/opt/X11/lib/pkgconfig pkg-config --libs bonmin`
Before XXX_LDFLAGS variable, obtained from PkgConfig module, is used in target_link_libraries call, modify that variable:
string(REPLACE "-framework;" "-framework " PKG_BONMIN_LDFLAGS "${PKG_BONMIN_LDFLAGS}")
(The quotation marks at "${PKG_BONMIN_LDFLAGS}" are important.)
After that, -framework option will be processed correctly:
target_link_libraries(... ${PKG_BONMIN_LDFLAGS})
Explanations
It seems that CMake incorrectly works with pkg-config when framework is used. When extract
-framework Acceletate
from the pkg-config output, these 2 words are interpreted as separate arguments. So, when passed to target_link_libraries:
target_link_libraries(... -framework Acceletate)
-l is appended to the second word according to the command's rules:
ld .... -framework -lAccelerate
Proper command's call should be
target_link_libraries(... "-framework Acceletate")
And this is exactly the purpose of above-mentioned string(REPLACE): It replaces CMake arguments delimiter ;, following -framework option, with normal space .
I have a C project which compiles successfully. Now I want to use C++ code in the same project, so I renamed main.c to main.cpp. The project is for an embedded microcontroller, so I'm cross compiling with the arm-none-eabi toolchain.
When I have renamed the main file to .cpp, I get the following error:
Linking CXX executable discovery_simple_test.elf
/usr/lib/gcc/arm-none-eabi/<long_path>/fpu/libg.a(lib_a-abort.o): In function `abort':
/build/<long_path>/newlib/libc/stdlib/abort.c:63: undefined reference to `_exit'
This is because some standard libraries are not available for this "bare metal" target. (see https://stackoverflow.com/a/13237079/507369)
This is solved in my linker script:
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
The linker script is added by my CMake toolchain file:
INCLUDE(CMakeForceCompiler)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)
# specify the cross compiler
CMAKE_FORCE_C_COMPILER(arm-none-eabi-gcc GNU)
CMAKE_FORCE_CXX_COMPILER(arm-none-eabi-g++ GNU)
SET(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/STM32F407VGTx_FLASH.ld)
SET(COMMON_FLAGS "-mcpu=cortex-m4 -mthumb -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -g -fno-common -fmessage-length=0")
UNSET(CMAKE_CXX_FLAGS CACHE)
UNSET(CMAKE_C_FLAGS CACHE)
UNSET(CMAKE_EXE_LINKER_FLAGS CACHE)
SET(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -std=c++11" CACHE STRING "" FORCE)
SET(CMAKE_C_FLAGS "${COMMON_FLAGS} -std=gnu99" CACHE STRING "" FORCE)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -Wl,-T ${LINKER_SCRIPT}" CACHE STRING "" FORCE)
My CMakeLists.txt looks like:
project(discovery_simple_test CXX C ASM)
add_definitions(-DSTM32F407xx)
file(GLOB_RECURSE USER_SOURCES "Src/*.c" "Src/*.cpp")
include_directories(Inc)
add_executable(${PROJECT_NAME}.elf ${USER_SOURCES} ${LINKER_SCRIPT})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.map")
When linking as a C executable, this works. When linking as a C++ executable I get the undefined reference error.
Update
I looked at the exact linker commands composed by CMake and those are:
For GCC (successful):
/usr/bin/arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mthumb-interwork
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections
-g -fno-common -fmessage-length=0 -std=gnu99 -Wl,-gc-sections
-T /path/STM32F407VGTx_FLASH.ld -Wl,
-Map=/path/build/discovery_simple_test.map
CMakeFiles/discovery_simple_test.elf.dir/Src/main.c.obj
<list of obj files>
-o discovery_simple_test.elf libCMSIS.a
For G++ (Error):
/usr/bin/arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mthumb-interwork
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections
-g -fno-common -fmessage-length=0 -std=c++11 -Wl,-gc-sections
-T /home/niels/Dev/stm32/discovery_simple_test/STM32F407VGTx_FLASH.ld
-Wl
-Map=/path/discovery_simple_test/build/discovery_simple_test.map
CMakeFiles/discovery_simple_test.elf.dir/Src/stm32f4xx_hal_msp.c.obj
CMakeFiles/discovery_simple_test.elf.dir/Src/stm32f4xx_it.c.obj
CMakeFiles/discovery_simple_test.elf.dir/Src/main.cpp.obj
<List of obj files>
-o discovery_simple_test.elf libCMSIS.a
So at least the parameters passed to g++ are the ones I expected. I tried removing --gc-sections in combination with adding -nostartfiles, but this didn't help.
I'm not sure if there's a more CMakeish way to do this, but try adding -specs=nosys.specs your CMake toolchain file like so:
SET(CMAKE_EXE_LINKER_FLAGS "-specs=nosys.specs, -Wl,--gc-sections -Wl,-T ${LINKER_SCRIPT}" CACHE STRING "" FORCE)
"nosys" is generic implementation for barebone systems.
https://launchpadlibrarian.net/170926122/readme.txt
The missing functions have to provide the interface between newlib and the hardware or the OS, these are called the system calls.
The linking issue can be solved by adding the --specs=nosys.specs command line option as stated by user Cinder Biscuits. This option provides mostly non-functional implementations of the system calls.
But this only solves the linking issue, if functionality from newlib is actually required, an implementation of the system calls needs to be provided.
A guide for developing the system calls can be found here.
For the STM32 microcontrollers, ST provides a file syscalls.c as part of their STM32CubeF4 software package. The file can be found in the package at Projects/STM32F4-Discovery/Examples/BSP/SW4STM32/. By adding this file to the project, implementations for all the syscalls are provided and newlib can be used.
For a small microcontroller like the STM32, newlib nano should be used as it is much smaller. This can be achieved by adding the --specs=nano.specs command line parameter.
Linking CXX executable discovery_simple_test.elf
/usr/lib/gcc/arm-none-eabi//fpu/libg.a(lib_a-abort.o): In function abort':
/build/<long_path>/newlib/libc/stdlib/abort.c:63: undefined reference to_exit'
The _exit function is part of newlib (check newlib/_exit.c ). Try adding following flag to the CMAKE_EXE_LINKER_FLAGS: --specs=nano.specs
As you are on a freestanding system it makes also sense to add -ffreestanding to both – C and C++ – compiler flags.