CMake: How to handle multiple versions of same libraries? - cmake

in my project I am using the header only library rapidjson v1.1.0.
└── my_project
├── CMakeLists.txt
├── src
│
├── 3rdParty/tiny_dnn (header only)
│ ├── CMakeLists.txt
│ ├── src
│ └── rapidjson_v0.2
│
└── rapidjson_v1.1.0
The problem is now that tiny-dnn has also included rapidjson (but an older version), so while i try to include tiny_dnn in the main CMakeLists.txt like include_directories(${PROJECT_SOURCE_DIR}/3rdParty/tiny_dnn) some conflicts arise from either tiny-dnn searches mine rapidjson or my project searches in tiny-dnn's rapidjson.
my_project CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(my_project)
# check the build type and set compiler and linker flags
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
IF(CMAKE_BUILD_TYPE MATCHES DEBUG)
message("Debug build")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -g -O0 -std=c++17 -Ddeveloper_build")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIC -g -O0")
ELSEIF(CMAKE_BUILD_TYPE MATCHES RELEASE)
message("Release build")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -O3 -std=c++17")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O3")
ELSE()
message(FATAL_ERROR "No build type specified")
ENDIF()
find_package(Boost COMPONENTS system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/3rdParty/tiny-dnn)
file(GLOB_RECURSE SOURCE_FILES src/*.cpp src/*.c)
set(SOURCE_FILES
${SOURCE_FILES})
add_executable(my_project ${SOURCE_FILES})
target_link_libraries(my_project ${Boost_LIBRARIES} pthread)
set_target_properties(my_project PROPERTIES SUFFIX ${CMAKE_BUILD_TYPE})
my_project.cpp
#include <tiny_dnn/tiny_dnn.h>
#include <rapidjson/rapidjson.h> // <- usr/local/include/rapidjson
int main(int argc, char **argv)
{
rapidjson::Document d; // <- uses rapidjson (v0.2) of tiny_dnn/cereal/external/rapidjson but in my project i would use /usr/local/include/rapidjson (v1.0.1)
return 0;
}

In general - don't. Force one client to use higher / better. Even if you walk around those problems, you are likely to violate one definition rule and get segfault later.

Related

Multiple undefined reference during linking of a CMake project using ARM toolchain

I'm developing a build system using CMake to build applications using the arm-none-eabi toolchain.
This is my folder structure:
project/
├── apps/
│ ├── test_app
│ │ ├── inc/
│ │ ├── src/
│ │ ├── CMakeLists.txt
├── arch/
│ ├── CMSIS/
│ ├── include/
│ ├── startup/
│ ├── CMakeLists.txt
├── cmake/
│ ├── toolchain-samd51.cmake
├── CMakeLists.txt
This is my top level CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(SMALL-FW LANGUAGES C)
add_subdirectory(arch)
add_subdirectory(apps/test_app)
This is the toolchain cmake file:
# Set target architecture
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Set compiler to use
set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
#set(CMAKE_LINKER "arm-none-eabi-ld")
# Clear default compiler and linker flags.
set(CMAKE_C_FLAGS "")
set(CMAKE_C_LINK_FLAGS "")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# FIX - Bypass compiler check
set(CMAKE_C_COMPILER_FORCED TRUE)
# Define common compiler and linker flags
set(ARM_OPTIONS
-mthumb
-mabi=aapcs-linux
-mcpu=cortex-m4
-mfpu=fpv4-sp-d16
-mfloat-abi=softfp
--specs=nano.specs
-mlong-calls
-DSAMD51
)
# Define compiler specific flags
add_compile_options(
${ARM_OPTIONS}
-D__SAMD51J19A__
-ffunction-sections
-Wall
)
# Define linker specific flags
add_link_options(
${ARM_OPTIONS}
#--specs=nano.specs
LINKER:--gc-sections
)
This is the CMakeList.txt inside the arch folder:
add_library(asf OBJECT
startup/startup_samd51.c
startup/system_samd51.c
)
# Every target that links against asf needs to know where the ASF headers are.
target_include_directories(asf PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS/Include
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Use the custom linker script provided with ASF.
target_link_options(asf PUBLIC
-T${CMAKE_CURRENT_SOURCE_DIR}/startup/samd51j19a_flash.ld
)
And this is the app CMakeLists.txt:
add_executable(APP)
target_sources(APP PRIVATE src/main.c src/module.c)
target_include_directories(APP PRIVATE inc/)
target_link_libraries(APP asf)
CMake is running fine when the CMAKE_C_COMPILER_FORCED options is set to true, but when I try to make the project it fails with multiple undefined references errors like the next one:
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7e-m+fp/softfp/newlib/libc/reent/../../../../../../../../newlib-4.2.0.20211231/newlib/libc/reent/sbrkr.c:51: undefined reference to _sbrk'`
I have tried using nosys.specs flag but similar errors occurs.
Try this, it looks like typo
# Define linker specific flags
add_link_options(
${ARM_OPTIONS}
--specs=nano.specs
--gc-sections
)

Make error with CppUTest - libCppUTest.a error adding symbols

I am trying to create a project folder structure based on CMake, using the gcc-arm-none-eabi toolchain, and that can use QEMU (arm) to run CppUTest.
Right now, my folder structure look like this:
project/
├── app/
│ ├── src/
│ │ └── main.cpp
│ ├── tests/
│ │ ├── CMakeLists.txt
│ │ ├── FooTest.cpp
│ │ └── main.cpp
│ ├── CMakeLists.txt
│ └── runCMake.sh
├── libraries/
│ ├── errortype/
│ │ ├── include/
│ │ ├── src/
│ │ └── CMakeLists.txt
│ ├── math/
│ │ ├── include/
│ │ ├── src/
│ │ └── CMakeLists.txt
│ └── prediction/
│ ├── include/
│ ├── src/
│ └── CMakeLists.txt
└── scripts/
└── cmake/
├── PreTargetDef.cmake
├── PostTargetDef.cmake
└── toolchain.cmake
The app/CMakeLists.txt:
### PROJECT INITIALIZATION
cmake_minimum_required(VERSION 3.19)
project(hello-arm)
### SET TOOLCHAIN
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/../scripts/cmake/toolchain.cmake)
### CUSTOM CMAKE SCRIPTS
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../scripts/cmake")
include(PreTargetDef)
### APPLICATION SOURCES
file(GLOB ${PROJECT_NAME}_SRC
"src/main.cpp"
)
### CREATE EXECUTABLE
add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRC})
### LIBRARIES TARGET INCLUDE DIRECTORIES
target_include_directories(${PROJECT_NAME} PUBLIC ${LIBERRORTYPE_INCLUDE_DIRS})
### CUSTOM CMAKE SCRIPT
include(PostTargetDef)
### OPTIONALLY COMPILE TESTS
option(COMPILE_TESTS "Compile the tests" OFF)
if(COMPILE_TESTS)
add_subdirectory(tests)
endif(COMPILE_TESTS)
Toolchain.cmake:
cmake_minimum_required (VERSION 3.6)
#set(CMAKE_CROSSCOMPILING 1)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(TRIPLE "arm-none-eabi")
unset(TOOLCHAIN_GCC_PROGRAM CACHE)
find_program(TOOLCHAIN_GCC_PROGRAM "${TRIPLE}-gcc" NO_DEFAULT_PATH HINTS ${ARM_CORTEX_COMPILER_PATH} $ENV{ARM_CORTEX_COMPILER_PATH})
get_filename_component(TOOLCHAIN_ROOT ${TOOLCHAIN_GCC_PROGRAM} DIRECTORY)
get_filename_component(EXE_EXT ${TOOLCHAIN_GCC_PROGRAM} EXT)
# To create static libraries suitable for link-time optimization (LTO),
# use gcc-ar and gcc-ranlib instead of ar and ranlib. See gcc -flto option
set(CMAKE_C_COMPILER "${TOOLCHAIN_ROOT}/${TRIPLE}-gcc${EXE_EXT}" CACHE FILEPATH "gcc" FORCE)
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_ROOT}/${TRIPLE}-g++${EXE_EXT}" CACHE FILEPATH "g++" FORCE)
set(CMAKE_OBJCOPY "${TOOLCHAIN_ROOT}/${TRIPLE}-objcopy${EXE_EXT}" CACHE FILEPATH "objcopy" FORCE)
set(CMAKE_OBJDUMP "${TOOLCHAIN_ROOT}/${TRIPLE}-objdump${EXE_EXT}" CACHE FILEPATH "objdump" FORCE)
set(CMAKE_RANLIB "${TOOLCHAIN_ROOT}/${TRIPLE}-gcc-ranlib${EXE_EXT}" CACHE FILEPATH "ranlib" FORCE)
set(CMAKE_STRIP "${TOOLCHAIN_ROOT}/${TRIPLE}-strip${EXE_EXT}" CACHE FILEPATH "strip" FORCE)
set(CMAKE_AR "${TOOLCHAIN_ROOT}/${TRIPLE}-gcc-ar${EXE_EXT}" CACHE FILEPATH "ar" FORCE)
set(CMAKE_AS "${TOOLCHAIN_ROOT}/${TRIPLE}-as${EXE_EXT}" CACHE FILEPATH "as" FORCE)
#SET(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs -Wl,-gc-sections -nostdlib -static-libgcc -static-libstdc++ -nostartfiles")
set(CMAKE_EXE_LINKER_FLAGS_INIT " --specs=nosys.specs ")
string(APPEND CMAKE_C_FLAGS_INIT " ")
string(APPEND CMAKE_C_FLAGS_INIT_DEBUG " ")
string(APPEND CMAKE_CXX_FLAGS_INIT " ")
string(APPEND CMAKE_CXX_FLAGS_INIT_DEBUG " ")
set(SHARED_LIBS OFF)
set(STATIC_LIBS ON)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH )
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH )
PreTargetDef.cmake:
### ENABLE LANGUAGES
enable_language(C)
enable_language(CXX)
enable_language(ASM)
### COMPILE TARGET TYPE
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
### CREATE BUILD DIRECTORY IF NOT ALREADY DONE
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build)
### OPTIONS
set(APP_ROOT ${CMAKE_SOURCE_DIR}/src)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 99)
set(CMAKE_EXE_LINKER_FLAGS --specs=rdimon.specs)
### COMPILE OPTIONS
list(APPEND COMPILE_OPTIONS
-mthumb
-mcpu=cortex-a9
-mfloat-abi=softfp
-mfpu=fpv4-sp-d16
-flto
-lm
-lc
-lrdimon
-Wall
$<$<CONFIG:RELEASE>:-g3>
$<$<CONFIG:RELEASE>:-Os>
)
add_compile_options(
${COMPILE_OPTIONS}
)
### ADD SUBDIRECTORIES FOR LIBRARIES
get_filename_component(COMMON_LIBRARIES_ROOT "${CMAKE_SOURCE_DIR}/../libraries/" ABSOLUTE)
get_filename_component(COMMON_LIBRARIES_BUILD_ROOT "${CMAKE_BINARY_DIR}/common_libraries/" ABSOLUTE)
add_subdirectory(${COMMON_LIBRARIES_ROOT}/errortype/src ${COMMON_LIBRARIES_BUILD_ROOT}/errortype)
add_subdirectory(${COMMON_LIBRARIES_ROOT}/math/src ${COMMON_LIBRARIES_BUILD_ROOT}/math)
add_subdirectory(${COMMON_LIBRARIES_ROOT}/prediction/src ${COMMON_LIBRARIES_BUILD_ROOT}/prediction)
set( LIBS
prediction
errortype
)
PostTargetDef.cmake:
### TARGET LINK LIBRARY
target_link_libraries(
${PROJECT_NAME}
${COMPILE_OPTIONS}
-Wl,-static
-Wl,--start-group
${LIBS}
-Wl,--end-group
)
And, tests/ CMakeLists.txt:
# (1) Look for installed version of CppUTest
if(DEFINED ENV{CPPUTEST_HOME})
message(STATUS "Using CppUTest home: $ENV{CPPUTEST_HOME}")
set(CPPUTEST_INCLUDE_DIRS $ENV{CPPUTEST_HOME}/include)
set(CPPUTEST_LIBRARIES $ENV{CPPUTEST_HOME}/lib)
set(CPPUTEST_LDFLAGS CppUTest CppUTestExt)
else()
find_package(PkgConfig REQUIRED)
pkg_search_module(CPPUTEST REQUIRED cpputest>=3.8)
message(STATUS "Found CppUTest version ${CPPUTEST_VERSION}")
endif()
# (2) Our unit tests sources
set(TEST_APP_NAME ${PROJECT_NAME}_tests)
set(TEST_SOURCES
mocks/IFooMock.cpp
FooTest.cpp
main.cpp
)
# (3) Take care of include directories
include_directories(${CPPUTEST_INCLUDE_DIRS} ../src/)
link_directories(${CPPUTEST_LIBRARIES})
# (4) Build the unit tests objects and link then with the app library
add_executable(${TEST_APP_NAME} ${TEST_SOURCES})
target_link_libraries(${TEST_APP_NAME}
${CPPUTEST_LDFLAGS}
${COMPILE_OPTIONS}
-Wl,-static
-Wl,--start-group
${LIBS}
-Wl,--end-group
)
Doing cmake -DARM_CORTEX_COMPILER_PATH="/path/to/gcc-arm-bin/" -DCOMPILE_TESTS=ON $PROJECT_PATH creates a Makefile in the build folder for the main application and a second one under the build/tests folder.
Running make produces a hello-arm file for the main app that runs under qemu-arm hello-arm just fine. But come time to make the tests/ part, I get the following error (make VERBOSE=1):
[ 91%] Building CXX object tests/CMakeFiles/hello-arm_tests.dir/main.cpp.obj
cd /home/tester/Documents/hello-qemu-arm/build/release/tests && /home/tester/miniconda3/envs/hello-qemu/bin/arm-none-eabi-g++ -I/home/tester/miniconda3/envs/hello-qemu/include -I/home/tester/Documents/hello-qemu-arm/application/tests/../src -I/home/tester/Documents/hello-qemu-arm/libraries/prediction/src/include -I/home/tester/Documents/hello-qemu-arm/build/release/common_libraries/prediction/src-config/include -I/home/tester/Documents/hello-qemu-arm/libraries/types/src/include -I/home/tester/Documents/hello-qemu-arm/build/release/common_libraries/types/src-config/include -I/home/tester/Documents/hello-qemu-arm/libraries/math/src/include -I/home/tester/Documents/hello-qemu-arm/build/release/common_libraries/math/src-config/include -I/home/tester/Documents/hello-qemu-arm/libraries/errortype/src/include -I/home/tester/Documents/hello-qemu-arm/build/release/common_libraries/errortype/src-config/include -I/home/tester/Documents/hello-qemu-arm/build/include -I/home/tester/Documents/hello-qemu-arm/libraries/etl/src/include -I/home/tester/Documents/hello-qemu-arm/libraries/etl/src/../config -O3 -DNDEBUG -mthumb -mcpu=cortex-a9 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -flto -lm -lc -lrdimon -Wall -g3 -Os -std=gnu++17 -MD -MT tests/CMakeFiles/hello-arm_tests.dir/main.cpp.obj -MF CMakeFiles/hello-arm_tests.dir/main.cpp.obj.d -o CMakeFiles/hello-arm_tests.dir/main.cpp.obj -c /home/tester/Documents/hello-qemu-arm/application/tests/main.cpp
[100%] Linking CXX executable hello-arm_tests
cd /home/tester/Documents/hello-qemu-arm/build/release/tests && /home/tester/miniconda3/envs/hello-qemu/bin/cmake -E cmake_link_script CMakeFiles/hello-arm_tests.dir/link.txt --verbose=1
/home/tester/miniconda3/envs/hello-qemu/bin/arm-none-eabi-g++ -O3 -DNDEBUG --specs=rdimon.specs "CMakeFiles/hello-arm_tests.dir/mocks/IFooMock.cpp.obj" "CMakeFiles/hello-arm_tests.dir/FooTest.cpp.obj" "CMakeFiles/hello-arm_tests.dir/main.cpp.obj" -o hello-arm_tests -L/home/tester/miniconda3/envs/hello-qemu/lib -lCppUTest -lCppUTestExt -mthumb -mcpu=cortex-a9 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -flto -lm -lc -lrdimon -Wall -g3 -Os -Wl,-static -Wl,--start-group ../common_libraries/prediction/libprediction.a ../common_libraries/errortype/liberrortype.a -Wl,--end-group
/home/tester/miniconda3/envs/hello-qemu/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /home/tester/miniconda3/envs/hello-qemu/lib/libCppUTest.a: error adding symbols: file format not recognized
collect2: error: ld returned 1 exit status
make[2]: *** [tests/CMakeFiles/hello-arm_tests.dir/build.make:131: tests/hello-arm_tests] Error 1
make[2]: Leaving directory '/home/tester/Documents/hello-qemu-arm/build/release'
make[1]: *** [CMakeFiles/Makefile2:296: tests/CMakeFiles/hello-arm_tests.dir/all] Error 2
make[1]: Leaving directory '/home/tester/Documents/hello-qemu-arm/build/release'
make: *** [Makefile:91: all] Error 2

add extern cmake directory without building it

I have a cmake project somewhere that I want to use in several other projects. Let's call it projA located at path /projA. I have built it in /projA/build. In this build folder there is some library /projA/build/lib.a.
Now if I want to create a new project B using project A in the folder /projB I know two options for the CMakeLists:
Solution A
cmake_minimum_required(VERSION 3.0)
project(projB)
add_executable(${PROJECT_NAME} projB.cpp)
add_subdirectory(/projA /projA/build)
target_link_libraries(${PROJECT_NAME} projA)
The problem is that this solution will create new make files in /projA/build and the project A will be built again. Furthermore each time I will switch to a new project using projA, projA will be built again. So that's not a good solution. I would like to not overwrite all the build folder each time I switch between two project using projA.
Solution B
cmake_minimum_required(VERSION 3.0)
project(projB)
add_executable(${PROJECT_NAME} projB.cpp)
link_libraries(${PROJECT_NAME} /projA/build/lib.a)
target_include_directories(${PROJECT_NAME} PRIVATE /projA/include)
# Include directories
target_include_directories(${PROJECT_NAME} PRIVATE /projA/deps/depA/include)
target_include_directories(${PROJECT_NAME} PRIVATE /projA/deps/depB/include)
...
This solution works, but it's not very beautiful. I have to add a line for each include directory of all dependencies of project A.
So my question is: Is there a way to do it properly?
If you want to build them entirely separately, you will need to go through the find_package infrastructure. Here's a complete example:
Project A
lib.h
#ifndef LIB_H
#define LIB_H
int lib();
#endif
lib.c
#include "lib.h"
int lib() { return 42; }
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(projA)
add_library(lib lib.c)
target_include_directories(lib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
# Export the target named lib for use in other projects
# from the build tree of this project.
export(TARGETS lib FILE projA-config.cmake)
Project B
main.c
#include <stdio.h>
#include <lib.h>
int main () {
printf("%d\n", lib());
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(projB)
# Import the targets defined by projA
find_package(projA REQUIRED)
add_executable(projB main.c)
target_link_libraries(projB PRIVATE lib)
Compilation steps:
I'm imagining the two directories are next to each other, like so:
$ tree
.
├── projA
│   ├── CMakeLists.txt
│   ├── lib.c
│   └── lib.h
└── projB
├── CMakeLists.txt
└── main.c
Now we can build project A:
$ cmake -S projA -B projA/build -DCMAKE_BUILD_TYPE=Release
...
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/projA/build
$ cmake --build projA/build/ -- -v
[1/2] /usr/bin/cc -I/path/to/projA -O3 -DNDEBUG -MD -MT CMakeFiles/lib.dir/lib.c.o -MF CMakeFiles/lib.dir/lib.c.o.d -o CMakeFiles/lib.dir/lib.c.o -c /path/to/projA/lib.c
[2/2] : && /usr/bin/cmake -E rm -f liblib.a && /usr/bin/ar qc liblib.a CMakeFiles/lib.dir/lib.c.o && /usr/bin/ranlib liblib.a && :
And now we'll build project B, and set the projA_ROOT variable to /path/to/projA/build so that find_package(projA) will succeed.
$ cmake -S projB -B projB/build -DCMAKE_BUILD_TYPE=Release -DprojA_ROOT=$PWD/projA/build
...
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/projB/build
$ cmake --build projB/build
$ cmake --build projB/build/ -- -v
[1/2] /usr/bin/cc -isystem /path/to/projA -O3 -DNDEBUG -MD -MT CMakeFiles/projB.dir/main.c.o -MF CMakeFiles/projB.dir/main.c.o.d -o CMakeFiles/projB.dir/main.c.o -c /path/to/projB/main.c
[2/2] : && /usr/bin/cc -O3 -DNDEBUG CMakeFiles/projB.dir/main.c.o -o projB /path/to/projA/build/liblib.a && :
Clearly, this is non-obvious, and it's also sort of minimal. To build your own packages correctly, you should carefully read these CMake documentation pages:
https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html
https://cmake.org/cmake/help/latest/command/install.html
https://cmake.org/cmake/help/latest/command/export.html
I would also suggest watching Craig Scott's talk "Deep CMake for Library Authors", here: https://youtu.be/m0DwB4OvDXk

CMake imported target found when configuring but generated build.make says target-NOTFOUND

I have a simple shared library libfool2.so with installed header fool2.h which are not from a CMake project. My project my_temp1 depends on fool2 so I write a FindFool2.cmake to make an imported target:
find_path(Fool2_INCLUDE_DIR fool2.h PATH_SUFFIXES fool2)
find_library(Fool2_LIB fool2)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Fool2
REQUIRED_VARS Fool2_INCLUDE_DIR Fool2_LIB
)
if(Fool2_FOUND AND NOT TARGET Fool2::Fool2)
add_library(Fool2::Fool2 SHARED IMPORTED)
set_target_properties(Fool2::Fool2 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Fool2_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${Fool2_LIB}"
)
endif()
The CMakeLists.txt for my_temp1 project is:
cmake_minimum_required(VERSION 3.3)
project(my_temp1)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules)
# FindFool2.cmake is in ${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_modules
find_package(Fool2 REQUIRED)
if (TARGET Fool2::Fool2)
message(STATUS "target found")
endif()
add_executable(my_temp1 main.cpp)
target_link_libraries(my_temp1 Fool2::Fool2)
Now
$ tree ../__install
../__install/
├── include
│   └── fool2
│   ├── fool2.h
│   └── version.h
└── lib
└── libfool2.so
$ tree .
.
├── cmake
│   └── cmake_modules
│   └── FindFool2.cmake
├── CMakeLists.txt
└── main.cpp
$ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install
# some output omitted
-- target found
-- Configuring done
-- Generating done
-- Build files have been written to: /OMITTED/my_temp1/_builds
$ cmake --build _builds
CMakeFiles/my_temp1.dir/build.make:82: *** target pattern contains no '%'. Stop.
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/my_temp1.dir/all' failed
make[1]: *** [CMakeFiles/my_temp1.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
$ head -n 85 _builds/CMakeFiles/my_temp1.dir/build.make | tail -n 10
# External object files for target my_temp1
my_temp1_EXTERNAL_OBJECTS =
my_temp1: CMakeFiles/my_temp1.dir/main.cpp.o
my_temp1: CMakeFiles/my_temp1.dir/build.make
my_temp1: Fool2::Fool2-NOTFOUND
my_temp1: CMakeFiles/my_temp1.dir/link.txt
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/OMITTED/my_temp1/_builds/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Linking CXX executable my_temp1"
$(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/my_temp1.dir/link.txt --verbose=$(VERBOSE)
The command $ cmake -H. -B_builds -DCMAKE_INSTALL_PREFIX=../__install finds fool2 because find_* commands searches in the CMAKE_INSTALL_PREFIX as well.
But why is there weird output my_temp1: Fool2::Fool2-NOTFOUND in build.make?
CMake version is 3.11.3
For IMPORTED library target value -NOTFOUND corresponds to absent IMPORTED_LOCATION property, corresponded to the library's path. You need to set that property for correctly work with IMPORTED target.
If you want CMake target to be a placeholder just for link with other libraries, use INTERFACE library target instead: such library target doesn't have library location.

How to stop CMake from linking against libstdc++

I have a very simple CMakeLists.txt for a C++ project, which builds a shared library:
add_library(foo SHARED
${HDR_PUBLIC}
${SOURCES})
When linking the library, CMake automatically uses -lstdc++. How can I stop it from doing this?
You can add -stdlib=libc++ to compiler flags.
Simple example:
cmake_minimum_required(VERSION 2.8.4)
project(test)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v -stdlib=libc++")
add_executable(test main.cpp)
Give output:
"/usr/bin/ld" ... -o test ... -lc++ ...
By default:
cmake_minimum_required(VERSION 2.8.4)
project(test)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v")
add_executable(test main.cpp)
Link to stdc++:
"/usr/bin/ld" ... -o test ... -lstdc++ ...
[update]
If you don't need to link to c++ lib at all - use '-nodefaultlibs' as linker flag and '-nostdinc++' to compiler flag. You may need to link some default libraries, like '-lSystem'.
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(yourtarget PROPERTIES LINKER_LANGUAGE C)
Source: http://cmake.3232098.n2.nabble.com/setting-LINKER-LANGUAGE-still-adds-lstdc-td7581940.html