I'm currently using Kate and Arduino IDE to develop a library for Arduinos (actually rather little is Arduino specific but it's easy to just upload examples from A-IDE to physical hardware). But now I've reached the point Kate is rather cumbersome to use so I tried to switch to CLion, the issue is that I can't get linting and compilation working in it. I tried using the Arduino plugin for CLion, it kind-of works for small examples, but fails for me, please keep in mind that Arduino IDE has no problem compiling my code and uploading it.
This is my CMakeFiles.txt:
cmake_minimum_required(VERSION 2.8.4)
set(ARDUINO_SDK_PATH ${HOME}/arduino-1.8.2/)
set(PROJECT_NAME MyLibrary)
project(${PROJECT_NAME})
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake)
add_library(./modules/lib1/lib1.h)
add_library(./modules/lib2/lib2.h)
add_library(./modules/lib3/lib3.h)
add_library(./modules/lib4/lib4.h)
set(EXAMPLE2_SKETCH ./examples/example2/example2.ino)
set(EXAMPLE1_SKETCH ./examples/example1/example1.ino)
generate_arduino_firmware(EXAMPLE2_SKETCH)
generate_arduino_firmware(EXAMPLE1_SKETCH)
Folder structure:
MyLibrary
├── drivers
│ └── HWLIB
│ ├── HWLIB.cpp
│ └── HWLIB.h
├── examples
│ ├── example1
│ │ └── example1.ino
│ └── example2
│ └── example2.ino
├── modules
│ ├── lib1
│ │ ├── lib1.cpp
│ │ └── lib1.h
│ ├── lib2
│ │ ├── lib2.cpp
│ │ └── lib2.h
│ ├── lib3
│ │ ├── lib3.cpp
│ │ └── lib3.h
│ └── lib4
│ ├── lib4.cpp
│ └── lib4.h
└── MyLibrary.h
1: After trying to refresh the cmakefile then CMake complains about almost every line and it doesn't make any sense:
CMake Warning (dev) at CMakeLists.txt:7 (add_library):
Policy CMP0037 is not set: Target names should not be reserved and should
match a validity pattern. Run "cmake --help-policy CMP0037" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
The target name "./modules/lib1/lib1.h" is reserved or not valid
for certain CMake features, such as generator expressions, and may result
in undefined behavior.
This warning is for project developers. Use -Wno-dev to suppress it.
You have called ADD_LIBRARY for library ./modules/lib1/lib1.h without any source files. This typically indicates a problem with your CMakeLists.txt file
CMake Warning (dev) at CMakeLists.txt:8 (add_library):
Policy CMP0037 is not set: Target names should not be reserved and should
match a validity pattern. Run "cmake --help-policy CMP0037" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
The target name "./modules/lib2/lib2.h" is reserved or
not valid for certain CMake features, such as generator expressions, and
may result in undefined behavior.
This warning is for project developers. Use -Wno-dev to suppress it.
You have called ADD_LIBRARY for library ./modules/lib2/lib2.h without any source files. This typically indicates a problem with your CMakeLists.txt file
CMake Warning (dev) at CMakeLists.txt:9 (add_library):
Policy CMP0037 is not set: Target names should not be reserved and should
match a validity pattern. Run "cmake --help-policy CMP0037" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
The target name "./modules/lib3/lib3.h" is reserved or not valid
for certain CMake features, such as generator expressions, and may result
in undefined behavior.
This warning is for project developers. Use -Wno-dev to suppress it.
You have called ADD_LIBRARY for library ./modules/lib3/lib3.h without any source files. This typically indicates a problem with your CMakeLists.txt file
CMake Warning (dev) at CMakeLists.txt:10 (add_library):
Policy CMP0037 is not set: Target names should not be reserved and should
match a validity pattern. Run "cmake --help-policy CMP0037" for policy
details. Use the cmake_policy command to set the policy and suppress this
warning.
The target name "./modules/lib4/lib4.h" is reserved or not
valid for certain CMake features, such as generator expressions, and may
result in undefined behavior.
This warning is for project developers. Use -Wno-dev to suppress it.
You have called ADD_LIBRARY for library ./modules/lib4/TooSigning.h without any source files. This typically indicates a problem with your CMakeLists.txt file
-- Generating NODE_SKETCH
CMake Error at cmake/Platform/Arduino.cmake:2130 (message):
ALL_SRCS not set: must define SRCS or SKETCH for target NODE_SKETCH
Call Stack (most recent call first):
cmake/Platform/Arduino.cmake:498 (required_variables)
CMakeLists.txt:22 (generate_arduino_firmware)
"You have called ADD_LIBRARY for library ./modules/lib3/lib3.h without any source files." but the header file specifies the source?
2: With that CMakefile CLion fails to find both standard libraries and other libraries in the modules folder. For example when viewing lib1.h I see these errors (marked red):
#include "modules/lib2/lib2.h"
^ Cannot find 'modules'
and
uint8_t variable = 0;
^ Can't resolve type 'uint8_t'
Same goes for Serial, memmove, malloc and etc.
Any ideas how I could fix these issues and use a proper IDE to develop my project?
It won't fix your whole project, due to doubtful design with MyLibrary.h. But try this for libraries:
Replace all of add_library(...) with just single include_directories(${CMAKE_CURRENT_SOURCE_DIR}/modules)
Then you can rewrite includes for modules like: #include <lib1/lib1.n>
Related
I am writing a library. I have the following structure:
src/
├── Logger
│ ├── CMakeLists.txt
│ ├── Logger.c
│ ├── Logger.h
├── Task
│ ├── CMakeLists.txt
│ ├── Task.c
└── ThreadPool
├── CMakeLists.txt
├── Thread.c
├── Thread.h
├── ThreadPool.c
├── ThreadPool.h
The CMakeLists.txt are very simple. I have a Top-Level CMakeLists.txt where I include these. So I get a static library for everything. Then I search for all object files and combine them to an libsomething.a file. (Not the best way to do it for now but I like cmake but need to learn more about compiling to understand the give functionality of cmake)
This works well an fits my needs BUT I need to link against libm if a compile an executable with my library and I really don't know why. I assume that this happens because I compile a static library without using libm.a or why?
I want the enduser just to link agains my library so he don't has to link agains other non libc parts. And I was not able to find any helpful information about this.
A static library is really nothing more than an archive of object files. Linking with a static library is equivalent to linking with all the individual object files from the library.
As such, the static library have no information about dependencies or other libraries needed. A static library isn't even linked, the object files are just added to the archive.
That's why you need to explicitly link with the dependencies of the static library yourself.
I'm kind of a beginner in c, and I would like to know if there's a way of making a package like in python, for example:
.
├── main.py
└── pkg
├── file1.py
├── file2.py
└── __init__.py
how would that look in c?
I'd imagine something like:
.
├── main.c
└── pkg
├── a.c
├── a.h
├── b.c
└── b.h
is it the way? if so how would that work? how would I use the stuff inside it?
There is nothing like this exact thing in C, it does not care about packages.
When you want to distribute a "package" you can build it as library, delivering the header files and precompiled libraries (static or dynamic, per OS and architecture, sometimes per compiler)
If you want to organize a big project into packages, just go ahead like your layout - your tools won't really care. You'd include headers of such "packages" by relative path from where you use it. Compilation depends on your toolchain, but generally you have one big project with all the sources.
I'm creating CMake OBJECT libraries which I need to combine later into a single SDK library.
I can install the files and package them with Conan.
add_library(mylib_OBJECTS OBJECT
# ...
install(TARGETS mylib mylib_OBJECTS
# object libraries
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR})
This makes cmake install the object libraries like this:
├── conaninfo.txt
├── conanmanifest.txt
└── lib
├── libmylib.a
└── objects-Release
└── mylib_OBJECTS
├── aio.o
├── atomic.o
├── bitmap.o
What cpp_info should I set to make Conan aware of that object library, and generate the correct FindMyLib.cmake file for it?
I have a C project:
.
├── build
├── bin
│ └── parser
├── CMakeLists.txt
├── configure.h.in
├── inc
│ ├── configure.h
│ ├── diam_dict.h
│ └── unit_tests.h
├── README.txt
├── src
│ └── diam_dict.c
└── testing
└── unit_tests.c
I want to put unit tests in the directory "testing", in the file "unit_tests.c".
I want to test all the functions of the file "src/diam_dict.c", what should I do to let "unit_tests.c" know where are the functions to test?
[what should I write in the file "unit_tests.c" and the top level cmake file "CMakeLists.txt"?]
(I should call all the functions of the source code file "diam_dict.c" to test them)
ps: The header file "diam_dict.h" contains all the prototypes of the functions in the source file "diam_dict.c", and the header file "unit_tests.h" cotains all the prototypes of the test file "unit_tests.c".
CMake is a build system, so you can combine it with any unit testing framework you wish.
As a matter of fact, CTest can call executables and check their result value, which allows some testing. But it is usually less fine granular compared to real unit test a known from dedicated unit testing frameworks.
I'm starting a new C project using CMake, so I created a directory structure very similar to the ones I use in Python (my "main" language). Although it compiles correctly, I'm not certain I'm doing it the right way. This is the current structure:
.
├── CMakeLists.txt
├── dist
│ └── # project will be built here, 'cmake ..'
├── extras
│ ├── CMakeLists.txt
│ ├── extra1
│ │ ├── CMakeLists.txt
│ │ ├── extra1.h
│ │ └── extra1.c
│ └── extra2
│ ├── CMakeLists.txt
│ ├── extra2.h
│ └── extra2.c
├── src
│ ├── CMakeLists.txt
│ ├── main.c
│ ├── module1.h
│ ├── module1.c
│ ├── module2.h
│ └── module2.c
└── test
├── CMakeLists.txt
├── test_module1.c
└── test_module2.c
Since all files are distributed across multiple directories, I had to find a way to locate the libraries present in extras and the ones I need to test in src. So, these are my CMakeLists':
./CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(MyProject)
add_definitions(-Wall -std=c99)
# I don't know really why I need this
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/dist)
add_subdirectory(src)
add_subdirectory(test)
add_subdirectory(extras)
enable_testing()
add_test(NAME DoTestModule1 COMMAND TestModule1)
add_test(NAME DoTestModule2 COMMAND TestModule2)
./src/CMakeLists.txt
macro(make_library target source)
add_library(${target} ${source})
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
endmacro(make_library)
make_library(Module1.o module1.c)
make_library(Module2.o module2.c)
./test/CMakeLists.txt
macro(make_test target source library)
add_executable(${target} ${source})
target_link_libraries(${target} Libtap.o ${library})
target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
endmacro(make_test)
make_test(TestModule1 test_module1.c Module1.o)
make_test(TestModule2 test_module2.c Module2.o)
./extras/CMakeLists.txt
# Hopefully you'll never need to change this file
foreach(subdir ${SUBDIRS})
add_subdirectory(${subdir})
endforeach()
(Finally) ./extras/libtap/CMakeLists.txt
add_library(Libtap.o tap.c)
target_include_directories(Libtap.o PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
So, now the question: the reason I'm worried is that this setup will create a 'public' library for every file I'm using, including extra libs (which are not meant to be distributed). If I have 10 libraries in src, 4 dependencies in extras (including libtap, which I'm using to test) and at least the same amount of test files, I'll end up with 24 compiled artifacts.
Is there any better way to expose libraries to linking?
I'm not compiling "main" yet, what would be the right configuration for that?
is add_definitions the right way to add flags to the compiler?
How can I make this structure more DRY?
Is there any better way to expose libraries to linking?
No, this seems fine.
You might however want to reconsider the granularity at which you create static libraries. For example, if all applications except the tests will only ever use Module1 and Module2 in combination, you might want to merge them into a single library target. Sure, the tests will link against parts of the component that they do not use, but that is a small price to pay for the decrease in build complexity.
I'm not compiling "main" yet, what would be the right configuration
for that?
There's nothing wrong with adding it to the src/CMakeLists.txt as well:
add_executable(my_main main.c)
target_link_libraries(my_main Module1.o Module2.o)
is add_definitions the right way to add flags to the compiler?
It can be used for that purpose, but might not be ideal.
Newer CMake scripts should prefer the target_compile_options command for this purpose. The only disadvantage here is that if you want to reuse the same compile options for all targets in your projects, you also have to do the same target_compile_options call for each of those. See below for tips on how to resolve that.
How can I make this structure more DRY?
First of all, unlike most program code, redundancy is often not that big an issue in build system code. The notable thing to look out for here is stuff that gets in the way of maintainability. Getting back to the common compiler options from before: Should you ever want to change those flags in the future, it is likely that you want to change them for every target. Here it makes sense to centralize the knowledge about the options: Either introduce a function at the top-level that sets the option for a given target, or store the options to a global variable.
In either case you will have to write one line per target to get the option, but it will not generate any maintenance overhead after that. As an added bonus, should you actually need to change the option for only one target in the future, you still have the flexibility to do so.
Still, take care not to overengineer things. A build system should first and foremost get things done.
If the easiest way to set it up means you copy/paste a lot, go for it! If during maintenance later it turns out that you have some real unnecessary redundancies, you can always refactor.
The sooner you accept the fact that your CMake scripts will never be as pretty as your program code, the better ;)
One small nitpick at the end: Avoid giving your target names extensions. That is, instead of
add_library(Libtap.o tap.c)
consider
add_library(Libtap tap.c)
CMake will automatically append the correct file ending depending on the target platform anyway.