CMakeLists creating an utility library - c

I'm learning how to use CMake to create a static libraries and share them the other modules in a project. The structure of the project is the following:
root
|
|__ util
| |
| |__ CMakeLists.txt
|
|__ execution
| |
| |__ CMakeLists.txt
|
|__ logic
| |
| |__ CMakeLists.txt
|
CMakeLists.txt
So I have a util module which contains some utility structures and function which are supposed to be used by the other modules (execution, logic). I have 2 misunderstandings:
I. Is it appropriate to simply add the headers of the util modules to the include path in the root/CMakeLists.txt and then link the util statically? Currently the util/CMakeLists.txt is the following:
add_library(util src/util.c)
II. In case the util library contains no source file and just common data-structures and definitions used by the other modules how can we add it? I tried to write util/CMakeLists.txt
add_library(util)
and then in the root/CMakeLists.txt
include_directories("${PROJECT_SOURCE_DIR}/util/include")
add_subdirectory(util)
But it didn't work.
You have called ADD_LIBRARY for library util without any source files.
This typically indicates a problem with your CMakeLists.txt file

Related

Build system output folder structuring

I want to make a public source library in C and I've been having a joyous time trying to work with both Makefiles and CMake. I like the simplicity of having one makefile per build partition but it's not cross-platform. I like the fact that CMake is cross-platform and although I hate the syntax types the language uses (I can get over that I guess..) it's the fact that when building, CMake floods my folders with a f*** tonne of cache files and I can't seem to change where they go. I would like to go with CMake since it seems to be more industry standard.
I like my builds in folders; Everything I care about in a seperate folder from all the build specific files that need to be generated. In visual studio I have this build structure and I would like to replicate it.
SolutionDir:
┝ Builds/
| ┝ Inter/ #For intermediate files
| | ┝ Debug/
| | | ┕ lib.o
| | ┕ Release/
| | ┕ lib.o
| ┝ Debug/ #For the debug build files
| | ┕ ProjectName/ ... .exe
| ┕ Release/ #For the release build files
| ┕ ProjectName/ ... .exe
┕ ProjectName/
┕ Source/
| lib.h
┕ lib.c
I cant even figure out how to make a sub directory in either systems for the build folder side, of course you can include sub directories for finding the source code so there must be a way? Any help would be greatly appreciated, I've been at this for too long now.
You can do whatever you want with makefiles, but since you ask about cmake, the only way to do it is to run the build from the build folder. In other words, you do this (assuming that you have SolutionDir/CMakeLists.txt):
cd SolutionDir
mkdir Builds
cd Builds
cmake ..
make -j8
(or whatever make command that you want). The Builds directory can be anywhere you want, it doesn't have to be within SolutionDir. You pass the directory containing the CMakeLists.txt file to cmake.

Manually specifying include directory for Swift C module

I have a C library MyLib that I am trying to use in a Swift app. I want to use a local copy of the library, so I don't want to install it or add my bridge header to its files. I clone the library to Sources/ClibMyLib/MyLib so the package structure looks like this:
App
| Package.swift
| Sources/
| ClibMyLib/
| module.modulemap
| bridge.h
| MyLib/
| include/
| myLibHeader.h
| source/
| *.c
I specify bridge.h as the header in the module map:
module ClibMyLib {
umbrella header "bridge.h"
link "MyLib"
export *
}
The problem is that the include directory of MyLib is not visible to bridge.h So if bridge.h looks like this:
#include "myLibHeader.h"
it fails to build since it can't find myLibHeader.h. If I specify the path from bridge.h to the local copy like this:
#include "MyLib/include/myLibHeader.h"
then any transitive includes in myLibHeader.h still fail.
This would be very easy to solve in a C build, I would just add MyLib/include as an include directory. I haven't been able to find a way to do something similar in Swift - most guides I have found install the library and include from /usr/local/include/.
Are my only options to place bridge.h in the library's include directory or to install the headers to /usr/local/include? Adding bridge.h to the library is not ideal, the include directory file structure is more complicated than the simple example I gave. I just want to be able to manually specify an include directory.

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)

Getting link errors with CMake

I'm getting multiple definition link errors after conditionally compiling platform-specific code.
My project is laid out like this:
/
|__+ include/
| |__+ native/
| | |__ impl.h
| |
| |__ general.h
|
|__+ src/
|__+ native/
| |__ impl.linux.c
| |__ impl.win32.c
|
|__ general.c
At the top of the general.c file:
#if defined(LIBRARY_PLATFORM_LINUX)
#include "native/impl.linux.c"
#elsif defined(LIBRARY_PLATFORM_WIN32)
#include "native/impl.win32.c"
#endif
I set up introspection in CMake in order to detect the operating system and define the corresponding constants. The thing is, I didn't want to maintain one CMakeLists.txt file in every directory, so I simply globbed all the .c files as suggested in this answer:
file(GLOB_RECURSE LIBRARY_SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/*.c")
Apparently, this is what is causing the problem. It seems to be compiling the code #included in general.c as well as the individual src/native/impl.*.c files.
CMakeFiles/lib.dir/src/native/impl.linux.c.o: In function `declared_in_impl_h':
impl.linux.c:(.text+0x0): multiple definition of `declared_in_impl_h'
CMakeFiles/lib.dir/src/general.c.o:general.c:(.text+0x0): first defined here
How can I untangle this situation?
The best practice for that sort of cross-platform situation is to create two libraries, one for linux and one for windows and stop doing conditional includes. Each platform only compiles and links the relevant library.
The recommended way to do that with cmake is to stop globbing and just include each file. There are some situations where it can get confused and not realize that it needs to recompile. You can make an argument that non-changing legacy code won't have that problem.
If you really want to avoid doing either of these things, I would put the included code in a header instead of a c file. You don't really want the include guards so that people don't get it confused for something that should be used like a regular header. Put a bunch of comments in the file to warn them off of said behavior as well.

Is there a C project Default Directory Layout?

I've always wanted to know if there is a default directory layout for C projects. You know, which folders should i put which files and such.
So I've downloaded lots of project's source codes on SourceForge and they were all different than each other.
Generally, I found more or less this structure:
/project (root project folder, has project name)
|
|____/bin (the final executable file)
|
|
|____/doc (project documentation)
| |
| |____/html (documentation on html)
| |
| |____/latex (documentation on latex)
|
|
|____/src (every source file, .c and .c)
| |
| |____/test (unit testing files)
|
|
|____/obj (where the generated .o files will be)
|
|
|____/lib (any library dependences)
|
|
|____BUGS (known bugs)
|
|____ChangeLog (list of changes and such)
|
|____COPYING (project license and warranty info)
|
|____Doxyfile (Doxygen instructions file)
|
|____INSTALL (install instructions)
| |
|____Makefile (make instructions file)
|
|____README (general readme of the project)
|
|____TODO (todo list)
Is there a default standard somewhere?
Edit: Sorry, really. I realised there are numerous similar questions for recommended C project directory files. But I've seen people say what they think is best. I'm looking for a standard, something that people usually follow.
Related Questions:
C - Starting a big project. File/Directory structure and names. Good example required
Folder structure for a C project
File and Folder structure of a App/Project based in C
Project Organization in C Best Practices
I would say "no", and your empirical evidence seems to support that.
I usually get confused right around when I need to decide between doc/ and docs/ ...
Well, there is “libabc” which is showcasing common practice.

Resources