CMake: How to add dependency on linker script for executable - cmake

I have a CMake script where the final executable is linked with my own linker script:
cmake_minimum_required(VERSION 3.1)
project(test_app)
set(LINKER_SCRIPT "linker.ld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T ${LINKER_SCRIPT}")
add_executable(${PROJECT_NAME}.elf
main.cpp
startup.cpp
)
How do I make an executable dependent also on the linker script file (trigger linking if linker.ld was changed)?

You can add a LINK_DEPENDS property to your executable target, using set_target_properties. Add the following line after your add_executable command:
set_target_properties(${TARGET_NAME} PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT})
The first argument to set_target_properties is the target name, i.e. the first argument you passed to add_executable.

I found this mail which described three possible ways for forcing an executable to be dependent on a linker script. Its author prefers this way:
CMakeLists.txt:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(LINKERSCRIPT C)
FILE(WRITE main.c "void main(){}")
# dummy.c must exist:
ADD_EXECUTABLE(EXE main.c dummy.c)
# linkerscript must exist:
SET_SOURCE_FILES_PROPERTIES(
dummy.c PROPERTIES OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/linkerscript
)
Here dummy.c is an empty file, which is listed for the add_executable() command only for make resulted executable dependent on the linker script via the OBJECT_DEPENDS property.

Related

How to create CMakeLists for this make file [duplicate]

Work on Ubuntu 16
I used g++ main.cpp -lpq command for compiler my small project. Now I use Clion and wanna do same what I do with g++. But I can't add compiler flags in cmake file and get compile error.
cmake_minimum_required(VERSION 3.5.1)
project(day_g)
set(CMAKE_CXX_FLAGS "-lpq")
add_definitions(-lpq)
message("CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(day_g ${SOURCE_FILES})
Also I run only cmake file and get CMAKE_CXX_FLAGS with -lpq flag.
CMAKE_CXX_FLAGS is -lpq
-- Configuring done
-- Generating done
How properly add compiler flags to cmake file?
Flag -l is for linker, not for compiler. This flag is used for link with libraries. CMake has special command target_link_libraries for that purpose:
target_link_libraries(day_g pq)
-lq is not a compiler flag (CFLAGS) but a linker flag.
To pass a library in a CMake project you should use:
target_link_libraries(target_name libraries...)
Note that if you specify 'q' as library the project will link with libq.a or, if you are on windows q.dll.
... in your CMakeLists.txt the correct line to add is:
target_link_libraries(day_g pq)
Note also that when you add a CFLAG you should also "remember" the previous ones that may be added by libraries or by your platform, ie:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
To check the exact flags cmake is passing to compiler or linker you can always run, from the build directory, the following command:
make VERBOSE=1

CMake having multiple executables throws me an error

I'm having some trouble with cmake: I'm using cmake for my school project and there is a bonus part but we have to compile another executable for the bonus part, and I tried this:
cmake_minimum_required(VERSION 3.10)
project(philosophers)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_COMPILER /usr/bin/clang)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-Wall -Wextra -Werror")
set(CMAKE_EXE_LINKER_FLAGS "-lpthread")
set(LIBFT ${CMAKE_CURRENT_SOURCE_DIR}/lib/libft42/libft.a)
add_custom_command(OUTPUT ${LIBFT}
COMMAND make
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib/libft42)
link_libraries(philo_bonus ${LIBFT})
link_libraries(philo ${LIBFT})
aux_source_directory(src SRC)
aux_source_directory(src_bonus SRC_BONUS)
add_executable(philo ${SRC} ${LIBFT})
add_executable(philo_bonus ${SRC_BONUS} ${LIBFT})
target_include_directories(philo
PUBLIC inc
PUBLIC lib/libft42/inc)
target_include_directories(philo_bonus
PUBLIC inc_bonus
PUBLIC lib/libft42/inc)
I removed include_directories and replaced it with target_include_directories because I want my two projects to have separate includes, but when I try to cmake -Bbuild -H., it says:
CMake Error at CMakeLists.txt:23 (add_executable):
Target "philo_bonus" links to itself.
CMake Error at CMakeLists.txt:22 (add_executable):
Target "philo" links to itself.
CMake Error: Cannot determine link language for target "philo_bonus".
CMake Error: CMake can not determine linker language for target: philo_bonus
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
I don't understand what happened here, I changed nothing in add_executable and it worked fine before I added another.

cmake linker error with library installed in custom path

I have compiled and installed with CMake the library SDL_bgi to a custom prefix /custom/prefix/. This library uses SDL2.
Now I want to use it in another project with the structure below but I get a linker error when I compile with make:
/usr/bin/c++ CMakeFiles/test.dir/test.cpp.o -o test -Wl,-rpath,/custom/prefix/lib: /custom/prefix/lib/libSDL_bgi.so
/usr/bin/ld: /custom/prefix/lib/libSDL_bgi.so: undefined reference to `SDL_DestroyWindow'
/usr/bin/ld: /custom/prefix/lib/libSDL_bgi.so: undefined reference to `SDL_CreateRenderer'
I have also written the file cmake/modules/FindSDL_bgi.cmake so that may be wrong as well.
If I compile with the following command I can compile correctly:
g++ test.cpp -I . -lSDL_bgi -lSDL2 -I /custom/prefix/include/ -L /custom/prefix/lib/
What am I doing wrongly?
Project structure:
cmake/modules/FindSDL_bgi.cmake
src/test/CMakeLists.txt
src/test/test.cpp
CMakeLists.txt
Libraries:
/usr/lib/libSDL.so
/usr/include/SDL.h
/custom/prefix/lib/libSDL_bgi.so
/custom/prefix/include/graphics.h
/custom/prefix/include/SDL2/libSDL_bgi.h
cmake/modules/FindSDL_bgi.cmake:
# - Try to find LibXml2
# Once done this will define
# SDL_BGI_FOUND - System has LibXml2
# SDL_BGI_INCLUDE_DIRS - The LibXml2 include directories
# SDL_BGI_LIBRARIES - The libraries needed to use LibXml2
# Hardcoded for now
set(SDL_BGI_PATH
/custom/prefix/
)
set(SDL_BGI_SEARCH_PATHS
/usr
/usr/local
/opt
${SDL_BGI_PATH}
)
find_path(SDL_BGI_INCLUDE_DIR graphics.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include
PATHS ${SDL2_SEARCH_PATHS}
)
find_library(SDL_BGI_LIBRARY
NAMES SDL_bgi
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS ${SDL2_SEARCH_PATHS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SDL_bgi REQUIRED_VARS SDL_BGI_LIBRARY SDL_BGI_INCLUDE_DIR)
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(programmi_kennedy)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
set(COMPAT_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/
)
find_package(SDL_bgi REQUIRED)
add_subdirectory(src/test)
src/CMakeLists.txt:
add_executable(test test.cpp)
target_include_directories(test PUBLIC ${SDL_BGI_INCLUDE_DIR})
target_link_libraries(test PRIVATE ${SDL_BGI_LIBRARY})
install(TARGETS test DESTINATION bin)
/custom/prefix/include/graphics.h:
#include <SDL2/SDL_bgi.h>
What I was missing is to link to SDL2 with find_package(SDL2 REQUIRED) and link to SDL2::SDL2. (I did try to link to ${SDL2_LIBRARIES} but the syntax is different now). Thanks to #KamilCuk to point me to the right direction.
EDIT:
I changed the FindBGI_sdl.cmake module in order to search for the dependencies (SDL2) and link against them using the INTERFACE keyword. In this way the target test can link only against SDL_bgi and have the dependencies resolved automatically.
src/CMakeLists.txt:
add_executable(test test.cpp)
target_link_libraries(test PRIVATE SDL_bgi::SDL_bgi)
install(TARGETS test DESTINATION bin)
cmake/modules/FindSDL_bgi.cmake:
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindSDL_bgi
-------
Finds the SDL_bgi library.
Imported Targets
^^^^^^^^^^^^^^^^
This module provides the following imported targets, if found:
``SDL_bgi::SDL_bgi``
The SDL_bgi library
Result Variables
^^^^^^^^^^^^^^^^
This will define the following variables:
``SDL_bgi_FOUND``
True if the system has the SDL_bgi library.
``SDL_bgi_VERSION``
The version of the SDL_bgi library which was found.
``SDL_bgi_INCLUDE_DIRS``
Include directories needed to use SDL_bgi.
``SDL_bgi_LIBRARIES``
Libraries needed to link to SDL_bgi.
Cache Variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``SDL_bgi_INCLUDE_DIR``
The directory containing ``foo.h``.
``SDL_bgi_LIBRARY``
The path to the SDL_bgi library.
#]=======================================================================]
find_package(SDL2 REQUIRED)
find_package(PkgConfig)
pkg_check_modules(PC_SDL_bgi QUIET SDL_bgi)
find_path(SDL_bgi_INCLUDE_DIR
NAMES graphics.h
PATHS ${PC_SDL_bgi_INCLUDE_DIRS}
)
find_library(SDL_bgi_LIBRARY
NAMES SDL_bgi
PATHS ${PC_SDL_bgi_LIBRARY_DIRS}
)
set(SDL_bgi_VERSION ${PC_SDL_bgi_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SDL_bgi
FOUND_VAR SDL_bgi_FOUND
REQUIRED_VARS
SDL_bgi_LIBRARY
SDL_bgi_INCLUDE_DIR
VERSION_VAR SDL_bgi_VERSION
)
if(SDL_bgi_FOUND AND NOT TARGET SDL_bgi::SDL_bgi)
add_library(SDL_bgi::SDL_bgi UNKNOWN IMPORTED)
set_target_properties(SDL_bgi::SDL_bgi PROPERTIES
IMPORTED_LOCATION "${SDL_bgi_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_SDL_bgi_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL_bgi_INCLUDE_DIR}"
)
target_link_libraries(SDL_bgi::SDL_bgi INTERFACE SDL2::SDL2)
endif()
mark_as_advanced(
SDL_bgi_INCLUDE_DIR
SDL_bgi_LIBRARY
SDL2_DIR
)
Useful references:
https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/
https://cmake.org/cmake/help/v3.17/manual/cmake-developer.7.html

how do i specify libraries's path to cmake which are used by target_link_libraries

I have some codebase which has cmake build system .while building iam getting an error as below
/usr/bin/ld: cannot find -lcurl
below is the sample cmakelist.txt
cmake_minimum_required(VERSION 2.8.6)
project(oci_object_test)
set(IB_HOME /home/user/sample_cmake/usr/lib)
include_directories(${LIB_HOME}/include)
link_directories(${LIB_HOME}/lib64)
link_directories(/home/user/sample_cmake/usr/lib/lib64)
link_directories(/home/user/)
set(SOURCES
sample.cpp
)
add_executable(demo ${SOURCES})
target_link_libraries(demo curl openssl)
for the above cmakelist.txt below is the link.txt generated by cmake
/usr/bin/c++ CMakeFiles/demo.dir/sample.cpp.o -o demo -L/home/user/sample_cmake/usr/lib/lib64 -L/home/user -rdynamic -lcurl -lopenssl -Wl,-rpath,/home/user/sample_cmake/usr/lib/lib64:/home/user
this issue is due to -lcurl getting added in link.txt generated by cmake . if i remove -lcurl from link.txt manually and build ,build will get success with no linker error . So is there any way i can get rid off this -lcurl in link.txt or is it possible to define -lcurl path where it actual libcurl present ( for example suppose libcurl present inside /usr/curl_path/curl) so that cmake could generate link.txt as below?
/usr/bin/c++ CMakeFiles/demo.dir/sample.cpp.o -o demo -L/home/user/sample_cmake/usr/lib/lib64 -L/home/user -rdynamic /usr/curl_path/curl -lopenssl -Wl,-rpath,/home/user/sample_cmake/usr/lib/lib64:/home/user
i know i can define libucrl path directly as below which will solve my issue ,
target_link_libraries(demo /usr/curl_path/curl openssl)
but iam looking for something like SET or any other cmake environment variable which i can define inside toolchain.cmake file so that cmakelist.txt is untouched ,in simple words how do i specify those libraries's path to cmake which are going use inside target_link_libraries
If your CMake version is less than 3.12, you need to use this old method. See:
https://cmake.org/cmake/help/v3.10/module/FindCURL.html
cmake_minimum_required(VERSION 3.10)
project(program)
find_package(CURL REQUIRED)
if (CURL_FOUND)
add_executable(program main.cpp)
target_link_libraries(program ${CURL_LIBRARIES})
target_include_directories(program PRIVATE ${CURL_INCLUDE_DIRS})
endif()
There is a new method for CMake 3.12 and later using imported targets. See the new alternative FindCurl.
cmake_minimum_required(VERSION 3.12)
project(program)
find_package(CURL REQUIRED)
if (CURL_FOUND)
add_executable(program main.cpp)
target_link_libraries(program CURL::libcurl)
endif()
I found out that this issue can be solved by two methods (first method is similar to this)
second method is by adding below two lines of code to your cmakelist.txt file before calling target_link_directories
add_library( curl SHARED IMPORTED)
set_property(TARGET curl PROPERTY IMPORTED_LOCATION "${CURL_LIBRARY}")
where CURL_LIBRARY is the path for libcurl.so specified in toolchain.cmake
unfortunately i didn't find any solution to solve this issue without touching cmakelist.txt.

How to get cmake generate -std=c++14 flag for qcc compiler

I'm trying to cross compile some c++ library for QNX neutrino using cmake. In CMakeLists.txt file I specified CMAKE_CXX_STANDARD 14 required, but the resulting compiler command line does not contain the -std=c++14 option.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
I've tried using target compile features:
target_compile_features(my_library PRIVATE cxx_std_14)
but that gives me the following error:
CMake Error at CMakeLists.txt:53 (target_compile_features):
target_compile_features no known features for CXX compiler
"QCC"
version 5.4.0.
When I'm using check_cxx_compiler_flag feature, it seems to recognize the option:
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++14 CXX14_SUPPORT)
if(CXX14_SUPPORT)
message("c++14 support found")
else()
message("c++14 unsupported")
endif()
This outputs message
c++14 support found
Running qcc manually it accepts the -std=c++14 option just fine and the code using std::make_unique compiles just fine.
Also using the native compiler (Ubuntu 18.04, gcc) everything work fine with cmake generated makefiles. make VERBOSE=1 displays the following command line (I removed some directories):
/usr/local/bin/c++ -Dshm_transfer_EXPORTS -I... -fPIC -std=gnu++14 -o CMakeFiles/shm_transfer.dir/src/SharedMemoryTransfer.cpp.o -c .../SharedMemoryTransfer.cpp
as opposed to the command line using qcc toolchain:
.../qnx700/host/linux/x86_64/usr/bin/qcc -lang-c++ -Vgcc_ntox86_64 -lang-c++ -Dshm_transfer_EXPORTS -I... -fPIC -o CMakeFiles/shm_transfer.dir/src/SharedMemoryTransfer.cpp.o -c .../SharedMemoryTransfer.cpp
I would have expected the cmake command to recognize that qcc supports the -std=c++14 option and generates the corresponding command lines because of the CMAKE_CXX_STANDARD setting.
Use
set_property(TARGET ${PROJECT_NAME} PROPERTY LINKER_LANGUAGE CXX)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
. Using this you can stick the compiler setting to the target, while global flags are dis encouraged and can be overwritten by other cmake consumers. This the reason I assume why the deprecated set(CMAKE_CXX_STANDARD 14) did not help you: I can not see your full CMakeLists.txt and bet you have many sub folders and other targets, which could reset the CMAKE_CXX_STANDARD them selfs. Also make sure of the ordering of the CMake commands.
And you can replace ${PROJECT_NAME} with my_library if you want.
add_compile_options(-std=gnu++14)
Add this to your project level CMakeLists.txt file, not in toolchain.