How to link multiple CMake files together? - c

I am new at CMake and I really don't find any helpful tutorials. If you can recommend one, I would appreciate it.
I have a project with this structure:
project-dir
|- dir1
|- c files (1.c)
|- headers (1.h)
|- dir2
|- dir3
|- c files (3.c)
|- headers (3.h)
|- dir4
|- c files (4.c)
|- headers (4.h)
|- c files (2.c)
|- headers (2.h)
|- c files (pro.c)
|- headers (pro.h)
|- main.c
In every directory there is a CMakeList.txt like this:
set(DIR1 1.c 1.h)
add_library(dir1_lib ${DIR1})
In the project directory the cmake file is bigger:
cmake_minimum_required(VERSION 3.21)
project(project_name VERSION 1.0 LANGUAGES C)
add_subdirectory(dir1)
add_subdirectory(dir2)
set(PRO
pro.c
pro.h
)
add_library(project_lib ${PRO})
include_directories(dir1)
include_directories(dir2)
include_directories(dir2/dir3)
include_directories(dir2/dir4)
add_executable(project_name main.c)
target_link_libraries(project_name dir1_lib)
target_link_libraries(project_name dir2_lib)
target_link_libraries(project_name dir3_lib)
target_link_libraries(project_name project_lib)
I would like to build the whole project as one but for instance the 3.c does not see the 2.h file. Like:
fatal error: 2.h: No such file or directory
The C and header files depends on each other like 3.h needs 2.h and 4.h needs 3.h and 1.h . I know it's so complicated but I'm sure there is a way to all the files sees each other. I tried to add include_directories() option to every CMake but it's not working.
That's how I tried:
set(DIR2 2.c 2.h)
add_library(dir2_lib ${DIR2})
include_directories(${PROJECT_SOURCE_DIR}/dir1)
include_directories(dir3)
include_directories(dir4)
#I added the subdirectory option too but still not working
add_subdirectory(dir3)
add_subdirectory(dir4)
I would like to build the whole project as one with multiple CMakes linked each other.

Related

How to create a library with CMakeLists.txt and include it in another program?

I'm new to C/C++ development and I'm struggling with CMakeLists.txt in CLion IDE.
I can't create a library (static or shared) that I can #include in another program.
I have this kind of structure :
src/
|
|---> utilities/
| |---> CMakeLists.txt
| |---> utilties.h
| |
| |---> file_utilities/
| | |---> file_utilities.h
| | |---> file_utilities.c
| ...
|
|---> my_app
|---> CMakeLists.txt
|---> main.c
I have generated a libutilities.so and a libutilities.a. In my main.c file, it works if I do a #include "../utilities/utilities.h" or #include "../utilities/file_utilities/file_utilities.h".
Worse, if I create another project, with another program and link my libutilities.so, the link seems to work, but still can't include my headers.
I've tried many configuration, many options in CMakeLists.txt but it has never worked until now.
Here is the CMakeLists.txt that I use for my library. I'm quite sure the problem is in this file.
cmake_minimum_required(VERSION 3.7)
project(utilities VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 11)
link_libraries(pthread)
link_libraries(ssl)
link_libraries(crypto)
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIRS})
file(GLOB_RECURSE SOURCES RELATIVES "*.c")
file(GLOB_RECURSE HEADERS RELATIVES "*.h")
add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})
set_target_properties(${PROJECT_NAME} PROPERTIES
PUBLIC_HEADER "${HEADERS}"
ARCHIVE_OUTPUT_DIRECTORY "lib"
LIBRARY_OUTPUT_DIRECTORY "lib"
OUTPUT_NAME ${PROJECT_NAME})
target_include_directories(${PROJECT_NAME} PUBLIC .)
target_link_libraries(${PROJECT_NAME} ${CURL_LIBRARIES})
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
I'd like to have something more like #include <utilities/utilties.h> as it's a library. But I can't make it works.
In the example I provided, the library is a simple "utils" library, but I have to create more that I'll have to deliver and be integrated in another program than mine.
I highly suggest reading this article, in which a fictional library target is created, starting from project structure to installing/exporting. From my understanding, the author has exactly the same goal as you do. The article has cleared up a lot of things for me when I started out. I also recomend the project structure laid out within.
Project structure:
libjsonutils
├── CMakeLists.txt
├── include
│ └── jsonutils
│ └── json_utils.h
├── src
│ ├── file_utils.h
│ └── json_utils.cpp
└── test
├── CMakeLists.txt
└── src
└── test_main.cpp
Specifically, you will want to take a look at Targets and Properties, where generator expressions are used to differentiate between the include dir at build time, and when installed:
target_include_directories(JSONUtils
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
The install process and exporting/importing of targets is explained a little later in This is how you do CMake. What the author wants to do is be able to use the library in other cmake projects (e.g. a target called "example"), simply by doing the following:
find_package(JSONUtils 1.0 REQUIRED)
target_link_libraries(example JSONUtils::JSONUtils)
In order to make this work, you will need to install and export the library. The author encourages this for installation:
include(GNUInstallDirs)
install(TARGETS JSONUtils
EXPORT jsonutils-export
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
And this for exporting:
install(EXPORT jsonutils-targets
FILE
JSONUtilsTargets.cmake
NAMESPACE
JSONUtils::
DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/JSONUtils
)
The export will place a file named findJsonUtils.cmake in the given destination. This file will be what you need to import the library in other projects by using the find_package mechanism.
All code samples in this post taken from Pablo Arias' linked article.
Your CMakeLists.txt is inside utilities try to use this.
src/utilities/CMakeLists.txt:
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
)
For the app you should have something like:
src/my_app/CMakeLists.txt:
target_link_libraries(${PROJECT_NAME} PRIVATE utilities)
and you should have simple
src/CMakeLists.txt:
add_subdirectory(utilities)
add_subdirectory(my_app)

CMake project build with multi CMakeLists.txt [duplicate]

I'm currently using recursive make and autotools and am looking to migrate to CMake for a project that looks something like this:
lx/ (project root)
src/
lx.c (contains main method)
conf.c
util/
str.c
str.h
etc.c
etc.h
server/
server.c
server.h
request.c
request.h
js/
js.c
js.h
interp.c
interp.h
bin/
lx (executable)
How should I go about this?
If there's never any source higher than the lx/src directory, then there's no need for the lx/CMakeLists.txt file. If there is, it should look something like this:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(lx)
add_subdirectory(src)
add_subdirectory(dir1)
add_subdirectory(dir2)
# And possibly other commands dealing with things
# directly in the "lx" directory
...where the subdirectories are added in library dependency order. Libraries that depend on nothing else should be added first, and then libraries that depend on those, and so on.
lx/src/CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(lx_exe)
add_subdirectory(util)
add_subdirectory(js)
add_subdirectory(server)
set(lx_source_files conf.c lx.c)
add_executable(lx ${lx_source_files})
target_link_libraries(lx server)
# also transitively gets the "js" and "util" dependencies
lx/src/util/CMakeLists.txt
set(util_source_files
etc.c
etc.h
str.c
str.h
)
add_library(util ${util_source_files})
lx/src/js/CMakeLists.txt
set(js_source_files
interp.c
interp.h
js.c
js.h
)
add_library(js ${js_source_files})
target_link_libraries(js util)
lx/src/server/CMakeLists.txt
set(server_source_files
request.c
request.h
server.c
server.h
)
add_library(server ${server_source_files})
target_link_libraries(server js)
# also transitively gets the "util" dependency
Then, in a command prompt:
mkdir lx/bin
cd lx/bin
cmake ..
# or "cmake ../src" if the top level
# CMakeLists.txt is in lx/src
make
By default, the lx executable will end up in the "lx/bin/src" directory using this exact layout. You can control what directory it ends up in by using the RUNTIME_OUTPUT_DIRECTORY target property and the set_property command.
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:RUNTIME_OUTPUT_DIRECTORY
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:set_property
Refer to target_link_libraries libs either by CMake target name, if the lib is built as a CMake target via add_library, or by full path to the library file otherwise.
See also, the output of "cmake --help-command target_link_libraries", or any other cmake command, and the full online documentation for cmake commands found here:
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#section_Commands
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:target_link_libraries
Steinberg VST3 library has a reusable method which recursively loops through subdirectories and adds them if they include a CMakeLists.txt file:
# add every sub directory of the current source dir if it contains a CMakeLists.txt
function(smtg_add_subdirectories)
file(GLOB subDirectories RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
foreach(dir ${subDirectories})
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${dir}/CMakeLists.txt")
add_subdirectory(${dir})
endif()
endif()
endforeach(dir)
endfunction()
https://github.com/steinbergmedia/vst3_cmake/blob/master/modules/SMTG_AddSubDirectories.cmake

cmake Headerfile include from static library

I'd like to build a static library with following structure :
Foo/
|-- CMakeLists.txt
|-- file1.c
|-- some_definitions.h
|-- drivers/
|-- file2.c
This is the cmake code
add_library(myHAL STATIC)
target_sources(myHAL
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/file1.c"
"${CMAKE_CURRENT_LIST_DIR}/drivers/file2.c"
)
target_include_directories(myHAL PUBLIC ${CMAKE_CURRENT_LIST_DIR}/)
target_include_directories(myHAL PUBLIC ${CMAKE_CURRENT_LIST_DIR}/drivers/)
file2 includes some_definitions.h . In some_definitions, there are some #defines located.
I am not able to build, the definitions are not found (e.g FLS_FEATURE_A undecleared (first use))
When I move the some_definitions.h in the drivers folder, I am able to build.
What I am doing wrong? I suppose the preprocessor does not lookup for the defines or some_definitions.h is not found.
you need to use the target_include_directory or the include_directory(on older cmake versions)
this will tell your cmake to add the directory to the include path (just like -I in regular make)
this actually was discussed in a previous thread: How to properly add include directories with CMake
just include_directories("${CMAKE_CURRENT_LIST_DIR}")

Including Libraries in Multiple Files C Lang

I am working on a C project and I like to keep myself organised. Thus, I have got multiple header files, files with functions for that header files and a main file.
|- Header Files
| |- hash_table.h
| |- linked_list.h
| |- dictionary.h
|- Source Files
| |- main.c
| |- hash_functions.c
| |- list_functions.c
| |- dictionary_functions.c
Will it be any problem if I include libraries such as #include <stdio.h> in each of that function file? Will it affect by any means the efficiency of my program?
No, there would not be any problem if you include same header file in multiple files.
When any header file is written it is written to avoid multiple inclusion.
To avoid multiple inclusion, macro pre-processors are often used. One such mostly used way is given below.
#ifndef SOME_SYMBOL
#define SOME_SYMBOL
// actual code goes here.
#endif
For example see the code of stdio.h file for Linux at : https://github.com/torvalds/linux/blob/master/arch/powerpc/boot/stdio.h
All modern headers use header guards. This means that the header checks if it has been included before and then skips it. Also the compiler is smart enough to figure out which functions defined in a header you actually use and only include those in object code.
No, the include file is a description of the library. The library itself is a separate binary file that is linked in the final stages of program assembly
No problems.
Standard header files are written that way.
See: http://en.wikipedia.org/wiki/Include_guard
Mutliple file Inclusion will not effect you untill you have a INCLUSION GAURD.So by thi sYou can also do one easy thing, That is by having Single header file (suppose includes.h) which will have all include files So that you can eliminate the Order of Inclusion problem with the cost of compilation time.

Integrating another program into existing program compiled with CMake

I'm trying to integrate a side program (Program B) into an existing program (Program A) compiled/built with CMake. Currently CMake handles finding all the resources for and compiling Program A. I would like to include a couple .h files that Program B points to, so I can embed some of Program B's .c code in Program A.
I've tried playing around with one of the CMakeLists.txt files and even added some .c files to the add_library() block, but I still receive an "undefined reference to THIS_FUNCTION" error on compile.
Thank you for your time!
EDIT: Here's part of the CMakeList.txt file I updated on the RPi
add_library(rtlsdr_shared SHARED
librtlsdr.c
tuner_e4k.c
tuner_fc0012.c
tuner_fc0013.c
tuner_fc2580.c
tuner_r82xx.c
gpu_fft.c #Added this and a couple other .c files
)
target_link_libraries(rtlsdr_shared
${LIBUSB_LIBRARIES}
)
EDIT 2:
Proj A => rtl-sdr
Proj B => gpu_fft
rtl-sdr/
CMakeLists.txt
build/
cmake/
include/
m4/
src/
CMakeLists.txt
gpu_fft/
makefile
I think you better should build program B as a shared library, and add to the include_directories of program A the includes of program B. Then target_link_libraries to your program A.
Edit:
What I have in mind is a project with this folder structure:
projA/
CMakeLists.txt
include/
src/
B/
CMakeLists.txt
include/
src/
The CMakeLists.txt in B is very classical and build the shared library libB.so (e.g. on linux, .dll on WIN32).
In the CMakeLists.txt of projA folder put:
# first build project B
add_subdirectory(B)
# add include directory of project B
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/B/include")
# [...] build here your project
# and finally:
target_link_libraries(A B)
I hope it helps
EDIT2:
To build shared libraries you can set:
OPTION(BUILD_SHARED_LIBS TRUE)
or simply
SET(BUILD_SHARED_LIBS TRUE)
EDIT 3:
You can also use it simply as an external library. Set libraries search path first:
LINK_DIRECTORIES(${yourPathToLibB})
Don't forget to
include_directories("${yourPathToLibB}/include")
too. And then just do
TARGET_LINK_LIBRARIES(A B)

Resources