How the use unit test in cmake in language C? - c

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.

Related

CMake import external library (GNU readline) using ExternalProject_Add()

I am really new (just a few weeks) to C and its bulding tools. Using the CMake documetation and some other guides I created a basic CMake project. This works as expectd.
Now I wanted to use some libraries in my project (GNU readline and cJSON).
The cJSON library also uses CMake so I managed to include it in my project without too much trouble.
The GNU readline library on the other hand uses ninja and autotools (if I'm not mistaken). This is where I'm facing issues.
I am trying to build the GNU readline library to link the static files later in my project.
In the CMake documetation I saw you could use ExternalProject_Add() for the purpose of configuring and building an external project.
Just to test this I created a simple Project using CMake with ExternalProject_Add().
My test project has the following layout:
test
├── cmake-build-debug
│   ├── CMakeFiles
│   │   ├── 3.23.2
│   │   │   └── CompilerIdC
│   │   │   └── tmp
│   │   ├── CMakeTmp
│   │   ├── readline.dir
│   │   └── test.dir
│   ├── readline-prefix
│   │   ├── src
│   │   │   ├── readline-build
│   │   │   └── readline-stamp
│   │   └── tmp
│   └── Testing
│   └── Temporary
├── install_dir
└── libraries
└── readline-8.2
├── doc
├── examples
│   ├── autoconf
│   └── rlfe
├── m4
├── shlib
└── support
The library source files are located in test/libraries/readline-8.2.
I want the build files to get installed in the test/install_dir.
With the following Code I manage to build the the files, but I get errors when building it.
This is the content of my CMakeLists.txt
cmake_minimum_required(VERSION 3.23)
project(test C)
set(CMAKE_C_STANDARD 11)
set(LIB_PATH ${CMAKE_SOURCE_DIR}/libraries)
set(READLINE_LIB_SRC ${LIB_PATH}/readline-8.2)
set(CONFIGURE_ARGS --enable-shared=no --enable-install-examples=no --prefix=${CMAKE_SOURCE_DIR}/install_dir)
add_executable(test main.c)
include(ExternalProject)
ExternalProject_Add(
readline
BUILD_IN_SOURCE TRUE
BUILD_ALWAYS TRUE
SOURCE_DIR ${READLINE_LIB_SRC}
CONFIGURE_COMMAND ${READLINE_LIB_SRC}/configure ${CONFIGURE_ARGS}
BUILD_COMMAND make
INSTALL_COMMAND make install
)
I also tried adding the BUILD_BYPRODUCTS option of the ExternalProject_Add, as I read that ninja could face problems detecting targets otherwise, but without success.
The errors I get in the install step are:
mv: cannot stat '/home/devel/CLionProjects/test/install_dir/lib/libreadline.a': No such file or directory
mv: cannot stat '/home/devel/CLionProjects/test/install_dir/lib/libhistory.a': No such file or directory
But when I look at these directories the files exist.
The output of the build and the error message can be found here: https://gist.github.com/symb10sis/041f879ef5fbd02bcfd9200746101890
I couldn't include it in this question directly as it would get flagged as spam otherwise.
I spent hours reading the documetation, guides and questions here on stackoverflow but with my current knowledge of CMake I am stuck.
What causes the build to think these files don't exist? Is my use of ExternalProject_Add() appropriate for this or am I missing something?
I would really appreciate any help :)

Using CLion to develop Arduino libraries

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>

Makefile header includes

I am developing a Makefile for an old project. The new Makefile is based on an older one I used successfully with other projects, but now I face an odd problem.
My project has the following form:
├── Makefile
└── src
├── folder1
│   ├── somefiles.c
│   └── somefiles.h
├── folder2
│   ├── problematic.h
│   ├── somefiles.c
│   ├── somefiles.h
│   └── subdir
│   └── included_file.h
└── folder3
├── somefiles.c
└── somefiles.h
My Makefile has the following line:
LIBRARY_INC_PATHS = $(addprefix -I, $(shell find . -name '*.h' -printf '"%h"\n' | sort -u))
In file problematic.h there is the line:
#include "subdir/included_file.h"
Which causes trouble. GCC says that there is no such file or directory.
If I change it to:
#include "included_file.h"
the problem vanishes, but this is not an acceptable solution in my case.
What modifications should I make to my makefile so I can include files from my C code using relative paths, instead of their name only?

Load custom library while using CDN

I have an app that uses a custom application-specific library (sap.ui.foo) which contains custom controls, views and controllers.
My deployment strategy is serving my custom library from the same server/port that is serving the index.html file.
I would also like to use SAP's CDN to load the OpenUI5 libraries (sap.m, etc).
I am using the Grunt/node tools that come with OpenUI5's GitHub repository.
When I load my application all locally (no CDN) it works perfectly, but is very slow (such a huge download payload I suppose) so I'm trying to use the CDN in hopes of improving startup performance.
My index.html looks like this: (edited after #codeworrior's answer):
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.ui.layout, sap.m, sap.ui.foo"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots='{
"ns":"./",
"sap.ui.foo": "./sap/ui/foo/"
}'
>
Here is my directory structure (which to my knowledge is "standard"):
src
├── foo
│ └── src
│ └── main
│ └── webapp
│ ├── index.html # start point
│ ├── resources
│ ├── test-resources
│ └── WEB-INF
├── sap.m
├── sap.ui.commons
...other sap libs...
└── sap.ui.foo
└── src
└── sap
└── ui
└── foo
└── # my controls...
and after a grunt build:production my "target" directory looks like this:
target
├── openui5-sap.m
├── openui5-sap.ui.commons
├── openui5-sap.ui.core
├── openui5-sap.ui.demokit
├── ...other sap libs...
├── openui5-sap.ui.foo
└── resources
└── sap
└── ui
└── foo
├── Bootstrap.js
├── controllers
├── controls
├── data
├── font
├── img
├── js
├── library.js
├── library-preload.json
├── models
├── tasks
├── themes
├── util.js
├── views
└── wrappers
But, after I do a grunt serve:target and hit the url http://localhost:8989/foo/, in Chrome's dev-tools I get:
failed to preload 'sap.ui.foo.library-preload': Not Found - sap.ui.ModuleSystem
Uncaught Error: failed to load 'sap/ui/foo/library.js' from ./sap/ui/foo/library.js: 404 - Not Found
The network tab shows me that the CDN files are being served just fine, but the files that I'm trying to serve locally (such as my custom lib's library.js and library-preload.json) are 404's.
Any advice on how to get my library to load?
If your library is stored in the usual way (reflecting the full qualified names in the folder structure), then it should be sufficient to define a corresponding entry in your data-sap-ui-resourceroots attribute:
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.ui.layout, sap.m, my.uilib"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots="{
ns:'./',
'my.uilib': './my/uilib/'
}">
</script>
If the structure is different, just adapt the path in the configuration. resourceRoots are configured early, so you could even specify your lib in the data-sap-ui-libs attribute.
But maybe you tried that already and it didn't work. Then the problem might have been with the spelling of the option. It's 'resourceroots', not 'resource-roots'.

How to use check library with CTest for unit testing in C

I have project in which I want to use check library for unit testing.
My current project is using CMake and has following structure:
.
├── CMakeLists.txt
├── COPYING
├── ChangeLog
├── README
├── src
│   ├── core
│ │   ├── CMakeLists.txt
│ │ └── main.c
│   ├── core-test
│ │   ├── CMakeLists.txt
│ │ └── main.c
│ └── scrypt
└── doc
└── protocol.txt
In core-test I have unit tests for core module. In scrypt-test I will have tests for scrypt module and so on.
Does using check with CTest make sense?
If yes: how do I connect unit test that use check to CMake/CTest project? Do I need additional configuration for CTest to interpret results from check-enabled executables?
Using check with CTest is possible, unfortunately not convenient.
When unit tests using check fail they will be counted as a failure in CTest. The problem is, that CTest doesn't show output of application that failed1. The other downside is that CTest doesn't count individual check tests, so a "single" failed test could mean multiple check tests. I wasn't able to find a way to make CTest interpret check results.
You can force printing of output by creating CTestCustom.cmake file in build directory (the same one in which you run make or ctest) with following contents:
set (CTEST_CUSTOM_POST_TEST "cat Testing/Temporary/LastTest.log")

Resources