How to add cppcheck and clang-format inside cmake? - cmake

I have a project where I want to run cppcheck and clang-format using cmake when building the project.
Here is my code and the output. What am I missing? The output does not run either the cppcheck and clang-format. Both programs are on my path.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
# set your relative path to the gcc compiler
SET(CMAKE_C_COMPILER "gcc")
project(eec_cmocka_example VERSION 1.0 LANGUAGES C)
include(cmake/cppcheck.cmake)
include(cmake/clang-format.cmake)
include(cmake/FetchCMocka.cmake)
file(GLOB_RECURSE TEST_SRC_FILES unit-tests/*.c)
file(GLOB_RECURSE SRC_FILES src/*.c)
add_executable(eec_cmocka_example main.c ${SRC_FILES} ${TEST_SRC_FILES})
target_compile_features(eec_cmocka_example PRIVATE c_std_99)
target_link_libraries(eec_cmocka_example PRIVATE cmocka-static)
enable_testing()
add_test(NAME eec_cmocka_example COMMAND eec_cmocka_example)
set_property(TARGET eec_cmocka_example PROPERTY LINK_FLAGS "${DEFAULT_LINK_FLAGS} -Wl,\
--wrap=get_rx_dali_flag,\
--wrap=set_led_frequency,\
--wrap=application_process")
cppcheck.cmake:
file(GLOB_RECURSE ALL_SOURCE_FILES src/*.c src/*.h)
add_custom_target(
cppcheck
ALL
COMMAND /usr/bin/cppcheck
--enable=warning,performance,portability,information,missingInclude
--suppress=missingIncludeSystem
--std=c99
--library=std.cfg
--template="[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)"
--verbose
--quiet
${ALL_SOURCE_FILES}
)
clang-format.cmake:
file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h)
add_custom_target(
clangformat
ALL
COMMAND /usr/bin/clang-format
-style=Microsoft
-i
${ALL_SOURCE_FILES}
)
Output:
arda#arda-VirtualBox:~/Desktop/eec/UnitTesting_example/build$ make clangformat
Built target clangformat
arda#arda-VirtualBox:~/Desktop/eec/UnitTesting_example/build$ make cppcheck
Built target cppcheck
arda#arda-VirtualBox:~/Desktop/eec/UnitTesting_example/build$ make
[ 0%] Built target cppcheck
[ 0%] Built target clangformat
Consolidate compiler generated dependencies of target cmocka-static
[ 22%] Built target cmocka-static
Consolidate compiler generated dependencies of target eec_cmocka_example
[ 77%] Built target eec_cmocka_example
Consolidate compiler generated dependencies of target cmocka
[100%] Built target cmocka
arda#arda-VirtualBox:~/Desktop/eec/UnitTesting_example/build$

Related

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.

CLion parses GCC errors?

I have a few CMake targets in my project that calls makefiles, which will call gcc.
When there is a build error it shows up on Messages>Build:
my_dir/my_file.c: In function 'my_func':
my_dir/my_file.c.c:52:5: error: expected ';' before '}' token
I wanted to click on it and go straight to my_dir/my_file.c.c:52:5, is that possible?
My Cmakelists.txt only has symbols and include folders for indexing purposes, no C build configuration since all of that is made in the makefiles.
EDIT
This is my CMakeLists.txt structure:
cmake_minimum_required(VERSION 3.7)
project(myexec)
set(CMAKE_CXX_STANDARD 99)
set(MakefileDir ${CMAKE_CURRENT_SOURCE_DIR}/make)
add_custom_target(
mytarget
ALL
WORKING_DIRECTORY ${MakefileDir}
COMMAND make all)
file(GLOB_RECURSE SRCS *.c)
file(GLOB_RECURSE HDRS *.h)
include_directories(
sometthing/inc
(...)
)
add_definitions(
-DMY_SYM=1
(...)
)
add_executable(myexec EXCLUDE_FROM_ALL ${SRCS} ${HDRS})

CMAKE - Add library don't work last turn of foreach

I have a CMakelist.txt :
cmake_minimum_required(VERSION 3.12)
project(test)
set(TEST_HOME ${CMAKE_CURRENT_SOURCE_DIR})
message("test SDK home directory: " ${TEST_HOME})
set(a true)
list(APPEND plugins a)
set(b true)
list(APPEND plugins b)
set(c true)
list(APPEND plugins c)
add_executable(test main.c)
foreach(plugin IN LISTS plugins)
if(${${plugin}})
file(GLOB ${plugin}-SRC "${TEST_HOME}/plugins/${plugin}/src/*.c")
message(${${plugin}-SRC})
add_library(slt_${plugin} SHARED ${${plugin}-SRC})
message(${plugin})
target_link_libraries(test slt_${plugin}.so)
endif()
endforeach()
TLDR: I turn for create libraries and link them to my executable.
But my last library isn't created, the output of my Makefile generate by this CMakelist.txt is :
Scanning dependencies of target slt_c
[ 12%] Building C object CMakeFiles/slt_c.dir/plugins/c/src/c.c.o
[ 25%] Linking C shared library libslt_c.so
[ 25%] Built target slt_c
Scanning dependencies of target slt_b
[ 37%] Building C object CMakeFiles/slt_b.dir/plugins/b/src/b.c.o
[ 50%] Linking C shared library libslt_b.so
[ 50%] Built target slt_b
[ 62%] Linking C executable minko
/usr/bin/x86_64-linux-gnu-ld: cannot find -lslt_a
/usr/bin/x86_64-linux-gnu-ld: cannot find -lslt_b
/usr/bin/x86_64-linux-gnu-ld: cannot find -lslt_c
And when I turn a to false. It's be who don't build.
I really don't know what cause this, I just start CMAKE with some tests. Thank you.

How to auto generate pkgconfig files from cmake targets

I would like to generate pkgconfig files in cmake from the targets. I started by writing something like this:
function(auto_pkgconfig TARGET)
get_target_property(INCLUDE_DIRS ${TARGET} INTERFACE_INCLUDE_DIRECTORIES)
string(REPLACE "$<BUILD_INTERFACE:" "$<0:" INCLUDE_DIRS "${INCLUDE_DIRS}")
string(REPLACE "$<INSTALL_INTERFACE:" "$<1:" INCLUDE_DIRS "${INCLUDE_DIRS}")
string(REPLACE "$<INSTALL_PREFIX>" "${CMAKE_INSTALL_PREFIX}" INCLUDE_DIRS "${INCLUDE_DIRS}")
file(GENERATE OUTPUT ${TARGET}.pc CONTENT "
Name: ${TARGET}
Cflags: -I$<JOIN:${INCLUDE_DIRS}, -I>
Libs: -L${CMAKE_INSTALL_PREFIX}/lib -l${TARGET}
")
install(FILES ${TARGET}.pc DESTINATION lib/pkgconfig)
endfunction()
This is a simplified version but it basically reads the INTERFACE_INCLUDE_DIRECTORIES properties and processes the INSTALL_INTERFACE of the generator expressions.
This works well as long as the include directories are set before calling auto_pkgconfig, like this:
add_library(foo foo.cpp)
target_include_directories(foo PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
${OTHER_INCLUDE_DIRS}
)
auto_pkgconfig(foo)
However, sometimes properties are set after the call to auto_pkgconfig, like this:
add_library(foo foo.cpp)
auto_pkgconfig(foo)
target_include_directories(foo PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
${OTHER_INCLUDE_DIRS}
)
However, this won't properly read the include directories anymore. I would like auto_pkgconfig to run after all the target properties are set. I could use generator expressions for this, by changing auto_pkgconfig to this:
function(auto_pkgconfig TARGET)
file(GENERATE OUTPUT ${TARGET}.pc CONTENT "
Name: ${TARGET}
Cflags: -I$<JOIN:$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>, -I>
Libs: -L$<TARGET_FILE_DIR:${TARGET}> -l${TARGET}
")
install(FILES ${TARGET}.pc DESTINATION lib/pkgconfig)
endfunction()
However, this will read the BUILD_INTERFACE instead of the INSTALL_INTERFACE. So is there another way to read target properties after they have been set?
According to the CMake documentation, the contents of INSTALL_INTERFACE are only available when calling install(EXPORT). Unless they extend CMake, it will be best to do something else to generate your PkgConfig files. Ideally you would have enough control over your install layout to make this easy.
However, this doesn't mean you can't do what you ask; it's just "Tony the Pony" levels of evil. I actually hesitated to post this. Please don't take this as a recommendation.
The idea is to use install(EXPORT) to have CMake generate the appropriate scripts. Then generate a dummy CMake project that uses the file(GENERATE OUTPUT ...) code you gave above; the dummy project will see the exported, ie. INSTALL_INTERFACE properties.
I initially tried to use install(CODE [[ ... ]]) to do this, but it also sees the $<BUILD_INTERFACE:...> view. I've asked about this on the CMake Discourse.
cmake_minimum_required(VERSION 3.16)
project(example)
# Dummy library for demo
add_library(example SHARED example.cpp)
target_compile_definitions(example
PUBLIC $<BUILD_INTERFACE:BUILD>
$<INSTALL_INTERFACE:INSTALL>)
target_include_directories(example
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)
# Here be dragons...
function(auto_pc TARGET)
file(CONFIGURE OUTPUT "pc.${TARGET}/CMakeLists.txt"
CONTENT [[
cmake_minimum_required(VERSION 3.16)
project(pc_#TARGET#)
find_package(pc_#TARGET# REQUIRED CONFIG)
file(GENERATE OUTPUT #TARGET#.pc
CONTENT [=[
Name: #TARGET#
Cflags: -I$<JOIN:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>, -I> -D$<JOIN:$<TARGET_PROPERTY:INTERFACE_COMPILE_DEFINITIONS>, -D>
Libs: -L$<TARGET_FILE_DIR:#TARGET#> -l#TARGET#
]=] TARGET "#TARGET#")
]] #ONLY NEWLINE_STYLE LF)
install(TARGETS ${TARGET} EXPORT pc_${TARGET})
install(EXPORT pc_${TARGET} DESTINATION "_auto_pc" FILE pc_${TARGET}-config.cmake)
file(CONFIGURE OUTPUT "pc.${TARGET}/post-install.cmake"
CONTENT [[
file(REAL_PATH "${CMAKE_INSTALL_PREFIX}" prefix)
set(proj "#CMAKE_CURRENT_BINARY_DIR#/pc.#TARGET#")
execute_process(COMMAND "#CMAKE_COMMAND#" "-Dpc_#TARGET#_DIR=${prefix}/_auto_pc" -S "${proj}" -B "${proj}/build")
file(COPY "${proj}/build/#TARGET#.pc" DESTINATION "${prefix}")
]] #ONLY NEWLINE_STYLE LF)
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/pc.${TARGET}/post-install.cmake")
endfunction()
auto_pc(example)
# Clean up install path
install(CODE [[ file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}/_auto_pc") ]])
This results in the following:
alex#Alex-Desktop:~/test$ cmake -S . -B build
...
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
alex#Alex-Desktop:~/test$ cmake --build build/
...
alex#Alex-Desktop:~/test$ cmake --install build --prefix install
-- Install configuration: ""
-- Installing: /home/alex/test/install/lib/libexample.so
-- Installing: /home/alex/test/install/_auto_pc/pc_example-config.cmake
-- Installing: /home/alex/test/install/_auto_pc/pc_example-config-noconfig.cmake
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build/pc.example/build
alex#Alex-Desktop:~/test$ ls install/
example.pc lib
alex#Alex-Desktop:~/test$ cat install/example.pc
Name: example
Cflags: -I/home/alex/test/install/include -DINSTALL
Libs: -L/home/alex/test/install/lib -lexample
This should make you sad. It makes me sad.
edit: off topic, since here, the pc files are generated manually
pkgconfig template files
motivation:
CMakeLists.txt should be the single source of truth (name, version)
pkgconfig files are about 10 times smaller than cmake files (cmake to pkgconfig is a lossy transformation)
template file: my_package.pc.in
prefix="#CMAKE_INSTALL_PREFIX#"
exec_prefix="${prefix}"
libdir="${prefix}/lib"
includedir="${prefix}/include"
Name: #PROJECT_NAME#
Description: #CMAKE_PROJECT_DESCRIPTION#
Version: #PROJECT_VERSION#
Cflags: -I${includedir}
Libs: -L${libdir} -l#target1#
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(my_library VERSION 1.1.2 LANGUAGES C
DESCRIPTION "example library")
add_library(my_library src/my_library.c)
# generate pc file for pkg-config
set(target1 my_library)
configure_file(my_package.pc.in
lib/pkgconfig/my_package.pc #ONLY)
based on: CMake generate pkg-config .pc
related: exporting targets to cmake files

Linking error -- openSSL to libcurl

I'm doing C++ using libcURL. I got the task to test functions in Travis CI. So I used .travis.yml to get libcurl-dev and libssl-dev to connect to the project. I installed them and checked cURL configuration:
SSL support: enabled (OpenSSL)
But as I was trying to make main test file i got list of errors (example)
`Linking CXX executable ../bin/TechProject_example
/usr/local/lib/libcurl.a(libcurl_la-openssl.o): In function ossl_recv:
openssl.c:(.text+0xf3): undefined reference to ERR_clear_error
openssl.c:(.text+0x11c): undefined reference to SSL_read
openssl.c:(.text+0x163): undefined reference to SSL_get_error`
and so on...
The only thing I was able to check is that libcurl is working properly. I placed
--without-ssl flag and got protocol error.
Also I used
`- sudo ln -fs /usr/lib/libcurl.so.4 /usr/local/lib/`
to avoid cmake error. (I'm not very good at UNIX command, so this can be a problem)
So how should properly connect openSSL to C++ project that has <curl/curl.h> ?
EDIT:
Here is CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project (TechProject)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(HEADERS ${PROJECT_SOURCE_DIR}/include/testclass.h)
set(HEADERS ${PROJECT_SOURCE_DIR}/include/catch.hpp)
set(SOURCES ${PROJECT_SOURCE_DIR}/sources/testclass.cpp)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_library (${PROJECT_NAME} STATIC ${SOURCES})
add_subdirectory(example)
add_subdirectory(tests)
find_library(FOO_LIB libcurl.a)
target_link_libraries(TechProject "${FOO_LIB}")
And CMakeLists.txt in tests subdir:
cmake_minimum_required(VERSION 2.8)
set(TESTS_FOR_PROJECT TechProject)
project(${TESTS_FOR_PROJECT}_tests)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF)
file(GLOB ${PROJECT_NAME}_sources "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
find_package(${TESTS_FOR_PROJECT})
include_directories(${${TESTS_FOR_PROJECT}_INCLUDE_DIRS}})
include_directories(${CPM_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_sources} ${${PROJECT_NAME}_headers})
target_link_libraries(${PROJECT_NAME} ${TESTS_FOR_PROJECT})
add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/fixtures $<TARGET_FILE_DIR:${PROJECT_NAME}>)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${PROJECT_NAME} -s -r compact WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin)