This is the way how I compile my cpp code:
g++ -I/usr/local/include/modbus `pkg-config glib-2.0 --cflags --libs` -L/usr/local/lib -lmodbus test-modbus.c -o test-modbus
with gcc it is working pretty fine. But I need to place it into CmakeList.txt and I tried this:
SET(GCC_COVERAGE_COMPILE_FLAGS "-I/usr/local/include/modbus -L/usr/local/lib")
SET(GCC_COVERAGE_LINK_FLAGS "-lmodbus")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" )
But with no success. Any ideas?
CMake aims to be platform- and compiler-independent, so you don't set specific compiler flags, but you tell CMake what you want to do. For example, the include_directories command adds directories to the include path (similar to gcc's -I option), target_link_libraries links a library (similar to gcc's -l) option, pkg_config can be called through the PkgConfig module, and so on.
Related
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
I am trying to write a proper CMake script for building an embedded project(STM32). Our project structure looks like this:
App/
....Module1/
....Module2/
Core/
....OwnFramework/
........CoreModule1/
........CoreModule2/
....CubeMXGeneratedCode/
........Core/ (there are more files and dirs, but they are not relevant)
...........Src/main.c (only important info is that main is here)
........Drivers/
....Libs/
........Lib1/ (for example ETL)
Right now there is one CMakeLists.txt file in root project dir, but this seems like a bad solution. I've tried adding CMakeLists into App/ and App/Module but then I would get linking errors (while looking at compile_commands I've seen that they were compiled with almost no flags).
./CMakeLists.txt (removed some non-important parts, like set variables that are obvious, so it's little bit shorter)
set(APP_INCLUDE_DIRECTORIES
${APP_DIR}/Module1
${APP_DIR}/Module2
)
set(CORE_INCLUDE_DIRECTORIES
${Core_DIR}/CoreModule1
${Core_DIR}/CoreModule2
)
set(FLAGS
"-Wl,--gc-sections")
set(CPP_FLAGS
"-fno-rtti -fno-exceptions -fno-threadsafe-statics")
set(CPU_PARAMETERS
-mcpu=cortex-m4
-mthumb
-mfpu=fpv4-sp-d16
-mfloat-abi=hard)
set(STARTUP_SCRIPT ${CUBEMX_DIR}/startup_stm32fxxxxx.s)
set(MCU_LINKER_SCRIPT ${CUBEMX_DIR}/STM32Fxxxxxxx_FLASH.ld)
set(CUBEMX_INCLUDE_DIRECTORIES
${CUBEMX_DIR}/Core/Inc
... and some more Inc dirs
set(PROJECT_INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}
${APP_INCLUDE_DIRECTORIES}
${CORE_INCLUDE_DIRECTORIES})
file(GLOB_RECURSE STM32CUBEMX_SOURCES
${CUBEMX_DIR}/Core/*.c
${CUBEMX_DIR}/Drivers/*.c
${CUBEMX_DIR}/Middlewares/Third_Party/FreeRTOS/Source/*.c)
file(GLOB_RECURSE PROJECT_SOURCES FOLLOW_SYMLINKS
${APP_DIR}/*.cpp
${APP_DIR}/*.c
${CORE_DIR}/*.cpp
${CORE_DIR}/*.c)
add_executable(${EXECUTABLE}
${STM32CUBEMX_SOURCES}
${PROJECT_SOURCES}
${STARTUP_SCRIPT})
target_compile_definitions(${EXECUTABLE} PRIVATE
${MCU_MODEL}
USE_HAL_DRIVER)
target_include_directories(${EXECUTABLE} PRIVATE
${CUBEMX_INCLUDE_DIRECTORIES}
${PROJECT_INCLUDE_DIRECTORIES})
target_compile_options(${EXECUTABLE} PRIVATE
${CPU_PARAMETERS}
${FLAGS}
-Wall
-Wextra
-Wpedantic
-Wno-unused-parameter
$<$<COMPILE_LANGUAGE:CXX>:
${CPP_FLAGS}
-Wno-volatile
-Wold-style-cast
-Wuseless-cast
-Wsuggest-override>
$<$<CONFIG:Debug>:-Og -g3 -ggdb>
$<$<CONFIG:Release>:-Og -g0>)
target_link_options(${EXECUTABLE} PRIVATE
-T${MCU_LINKER_SCRIPT}
${CPU_PARAMETERS}
-Wl,-Map=${CMAKE_PROJECT_NAME}.map
--specs=nosys.specs
-Wl,--start-group
-lc
-lm
-lstdc++
-lsupc++
-Wl,--end-group
-Wl,--print-memory-usage)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${EXECUTABLE}>)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${EXECUTABLE}>
${EXECUTABLE}.hex
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${EXECUTABLE}>
${EXECUTABLE}.bin)
There is also toolchain file:
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(TOOLCHAIN_PREFIX arm-none-eabi-)
set(FLAGS
"-fdata-sections -ffunction-sections \
--specs=nano.specs -Wl,--gc-sections")
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc ${FLAGS})
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++ ${FLAGS})
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
I am building everything with this command:
cmake -B${workspaceFolder}/build -DCMAKE_TOOLCHAIN_FILE=gcc-arm-none-eabi.cmake -DCMAKE_BUILD_TYPE=Debug
And this setup works, but I have a feeling that this is a vary bad way of doing it. When I tried adding subdirectories in App and each module, I've got linking erros due to problems with compile flags (arm none eabi elf uses VFP register arguments linking error).
I am also not sure how well will it work when I start adding libs like Embedded Template Library.
So my question is, how do I add subdirectories so they compile the same way my root CMakeLists does? I've tried doing this following multiple guides and examples like this one: https://github.com/rgujju/STM32_Base_Project/blob/master/modules/simple_module/CMakeLists.txt.
But when I've put this in my App/Module/CMakeLists.txt
set(MODULE_NAME simple_module)
file(GLOB SOURCES ./*.c)
add_library(${MODULE_NAME} STATIC
${SOURCES}
)
target_include_directories(${MODULE_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
${PROJECT_SOURCE_DIR}/include
)
And added add_subdirectory(App) to main, my generated commands for modules where without most of my flags and didn't link.
If anyone has experience with dividing CMake project into modules, libs and subdirectories, I would gladly accept any help.
When trying to compile my project using the toolchain provided by the manufacturer of the hardware I'm developing for, compilation succeeds, however linking fails with the following error messages:
/media/xxx/Data/toolchains/sysroots/x86_64-xxx-linux/usr/bin/arm-xxx-linux-gnueabi/../../libexec/arm-xxx-linux-gnueabi/gcc/arm-xxx-linux-gnueabi/4.8.4/ld: cannot find -latomic
/media/xxx/Data/toolchains/sysroots/x86_64-xxx-linux/usr/bin/arm-xxx-linux-gnueabi/../../libexec/arm-xxx-linux-gnueabi/gcc/arm-xxx-linux-gnueabi/4.8.4/ld: cannot find -lstdc++
However, when building a small test program using the same compiler and linker, everything works.
Below is an excerpt of the important parts of my CMake toolchain file:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
###
# Get $CROSS
###
if (NOT $ENV{CROSS_COMPILE} STREQUAL "")
set(cross $ENV{CROSS_COMPILE}) # WARNING: Ends with a - (minus)
else()
set(cross "arm-xxx-linux-gnueabi-")
endif()
###
# Set CMake sysroot
###
set(CMAKE_SYSROOT $ENV{SDKTARGETSYSROOT})
set(CMAKE_SYSROOT_LINK $ENV{SDKTARGETSYSROOT})
set(CMAKE_SYSROOT_COMPILE $ENV{SDKTARGETSYSROOT})
set(CMAKE_C_COMPILER $ENV{TOOLCHAIN_TOOLSDIR}/${cross}gcc)
set(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN_TOOLSDIR}/${cross}g++)
set(CMAKE_LD $ENV{TOOLCHAIN_TOOLSDIR}/${cross}ld)
set(CMAKE_STRIP $ENV{TOOLCHAIN_TOOLSDIR}/${cross}strip)
set(CMAKE_AR $ENV{TOOLCHAIN_TOOLSDIR}/${cross}ar)
include_directories($ENV{SDKTARGETSYSROOT}/usr/include)
I'm not at liberty to disclose source code, but the source code isn't the issue here as it compiles correctly.
Here's another MWE of the CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10)
project(xxx LANGUAGES CXX VERSION 2.0.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(TARGET_NAME xxx.bin)
include_directories(
include/
${INCLUDE_DIRS}
)
file(GLOB_RECURSE FILES ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS src/*.cpp)
if (xxx_DEBUG)
add_compile_options(
-Wpedantic
-DDDC_STUB
-fabi-version=6
-Wno-format-security
-Wno-reorder
-ggdb3
-O0
-fpermissive # Test
-fPIC
#-static-libstdc++ # with or without, doesn't change the behaviour
#-static-libgcc # with or without, doesn't change the behaviour
)
else()
add_compile_options(
-Wpedantic
-fabi-version=6
-Wno-format-security
-Wno-reorder
-O3
-fpermissive # Test
-fPIC
#-static-libstdc++ # with or without, doesn't change the behaviour
#-static-libgcc # with or without, doesn't change the behaviour
)
endif()
add_executable(${TARGET_NAME} ${FILES} ${MEMWATCH_FILES})
I've tried setting the sysroot-argument for ld, I've tried manually specifying the link (search) path -L$ENV{SDKTARGETSYSROOT}/usr/lib/.debug, and I've also tried hard-wiring the path to the library in question: $ENV{SDKTARGETSYSROOT}/usr/lib/.debug/libatomic.so.1.0.0
Is there another way I can tell ld what libraries to use?
This works perfectly with standard toolchains!
EDIT:
I've now also tried brute-forcing it by creating a symlink from the .debug/libatomic to usr/lib/libatomic. That also hasn't had the desired effect.
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
I'm trying to build my project using curl, but I have this result :
undefined reference to `_imp__curl_easy_init'
This is my CMakeLists :
cmake_minimum_required(VERSION 2.8)
project(score)
set(SOURCE_FILES main.cpp)
add_executable(score ${SOURCE_FILES})
add_library(libcurl STATIC IMPORTED)
set_property(TARGET libcurl PROPERTY IMPORTED_LOCATION "c:/MinGW/lib")
SET(GCC_COVERAGE_LINK_FLAGS "-lcurl")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" )
Moreover, I put my file libcurl.a, etc... in the correct directory "c:/MinGW/lib".
Could you help me ?
You probably need to compile the source files that call the curl functions with the CURL_STATICLIB macro defined.
Do you have access to the curl-config utility? It's there when you build curl from source. Run it with the --cflags option to get the compiler flags required and the --libs option to get linker requirements.
For example, in my mingw environment, the cflags reported are -DCURL_STATICLIB -I/mingw/local/include and the lib flags reported are -L/mingw/local/lib -lcurl -lssl -lcrypto -lgdi32 -lwldap32 -lz -lws2_32.