CMake and CMocka standard assertions for compiling tests - c

I have a small static library project that I'm rewriting from building with Makefiles to modern CMake, which I am trying to learn.
My project uses assertions quite heavily for checking preconditions, so I have written a very simple custom assertion macro that conditionally expands into a function that prints formatted diagnostics and then aborts if the library was compiled in debug mode, or expands to nothing if the library was compiled in release mode.
However, I want to be able to test whether these assertions fire correctly. Cmocka allows you to test this by calling mock_assert in library code, which cmocka will intercept as part of testing. To this end, I want to have another macro, say LIBRARY_TESTING, that will redefine my custom assertion macro to invoke mock_assert instead of my own assertion function, so assertions can be tested. The final assertion macro can be considered morally equivalent to the following:
// In file include/assertion.h
#ifdef LIBRARY_DEBUG
#ifdef LIBRARY_TESTING
// mock_assert is provided by cmocka
void mock_assert(
int const result,
char const *const expression,
char const *const file,
int const line);
#define ASSERT(cond) \
mock_assert((cond), #cond, __FILE__, __LINE__)
#else
// emit_assertion is defined in src/assertion.c
void emit_assertion(int cond, char const *const msg);
#define ASSERT(cond) emit_assertion((cond), #cond)
#endif
#else
#define ASSERT(cond) // Nothing
#endif
I have been able to get the desired behaviour for building in debug mode (where ASSERT expands to a call to emit_assertion) and release mode (where ASSERT expands into nothing, as desired) through the following Cmake snippet in src/CMakeLists.txt):
target_compile_options(library PRIVATE
$<$<CONFIG:Debug>:-Og -ggdb3 -DLIBRARY_DEBUG >>
$<$<CONFIG:Testing>:-Og -ggdb3 -DLIBRAY_DEBUG -DLIBRARY_TESTING >>
)
From which building with either -DCMAKE_BUILD_TYPE=Debug or -DCMAKE_BUILD_TYPE=Release produces the intended behaviour. Extrapolating how CONFIG works here, I also added a generator expression that checks Testing, which defines BASIC_TESTING when compiling. All is well so far.
I start to run into problems when executing unit tests. For the purposes of exposition, the function that I want to test is equivalent to this, defined in include/example.h:
static inline bool example(int *arg)
{
ASSERT(arg != NULL);
return *arg == 0;
}
With a corresponding unit test in tests/example.c:
#include "example.h"
#include <cmocka.h>
// Other cmocka required #includes
static void test_example(void **state)
{
(void) state;
expect_assert_failure(example(NULL));
}
And the contents of test/CMakeLists.txt:
add_executable(example
${CMAKE_CURRENT_SOURCE_DIR}/example.c
)
add_test(example example)
target_include_directories(example PRIVATE
"${PROJECT_SOURCE_DIR}/include"
)
# 'library' is the static library target defined in the top-level
# CMakeLists.txt
target_link_libraries(example library cmocka)
Now, in order to unit test my library, I want my custom assertions to expand to mock_assert, so I compile my library for testing (as I understand it):
# In ./build
$ cmake -DCMAKE_BUILD_TYPE=Testing .. && make
Everything builds correctly and I have my static library liblibrary.a where I expect it to be. Additionally, my test executable example also compiles and links successfully, but when I run it, the test fails with a segmentation fault as if my custom assertion was never called (and the function attempts to dereference the NULL pointer I intentionally gave it to trigger the assertion). I am reasonably confident that there were no issues linking with cmocka itself, because running the test results in cmocka's fancy command-line output formatting.
In my original makefile-oriented build, all test executable targets would compile a special "testing" library target, and the test executables link to this library target and all assertions are correctly intercepted by cmocka as I would expect. However, in this case, it appears as if the static library I compiled is behaving as if neither LIBRARY_DEBUG or LIBRARY_TESTING were defined -- as evidenced by the segmentation fault.
I'm very new to modern cmake, so I feel like I am misunderstanding something conceptual. My question is:
How can I ensure that my static library is compiled with a particular (set of) compilation option(s) (here it is -DBASIC_TESTING) to ensure that the custom assertions that it fires can be tested with cmocka?

I solved this problem by defining a new library target specifically for building the testing library, and linked all test executables to the testing library.
I had to set the compile options on the testing library target to PUBLIC for these options to apply to building the testing targets. I then no longer had any use for the generator expression in the compile options for library-testing as it was implied that this target will only ever be built for linking with testing executables.
In src/CMakeLists.txt
add_library(
library,
src/example.c)
+add_library(
+ library-testing,
+ src/example.c)
target_compile_options(library PRIVATE
$<$<CONFIG:Debug>:-Og -ggdb3 -DLIBRARY_DEBUG >>
)
+target_compile_options(library-testing PUBLIC
+ -Og -ggdb3 -DLIBRARY_DEBUG -DLIBRARY_TESTING
+)
And then in test/CMakeLists.txt:
add_executable(example
${CMAKE_CURRENT_SOURCE_DIR}/example.c
)
add_test(example example)
target_include_directories(example PRIVATE
"${PROJECT_SOURCE_DIR}/include"
)
# Link with library-testing target instead of library target
-target_link_libraries(example library cmocka)
+target_link_libraries(example library-testing cmocka)
After making these changes my test executables all behaved as expected.

Related

Optional dynamic library

Background
Trying to profile an executable, I experimented the profiler Intel VTune and I learn that there is an API library (ITT) that provide utility to start/stop profiling. Its basic functions __itt_resume() and __itt_pause(). What triggers me is that the library is optional, i.e. if the runtime library of ITT is not loaded, these functions are basically noops.
Optional library?
I want to know (first of all on Linux)
Does a process checks that the dynamic library he is linking to is loaded when he starts or when each symbol, or the first symbol of the library is called at runtime (i.e. lazy initialization)? I think on Windows it's at startup because of can't find XXX.dll messages, but I am not sure on Linux. Also, with the example, I don't get any compilation & execution issues even if the symbol is not defined in some_process.c.
How to implement this on Linux? Looking at the Github repo of ITT, among many macro trickery, I feel like the key is here:
#define ITTNOTIFY_VOID(n) (!ITTNOTIFY_NAME(n)) ? (void)0 : ITTNOTIFY_NAME(n)
Basically it wraps every function call with a function pointer call if its not NULL.
How to implement this in a cross-platform way (Windows, Mac, Linux) ?
I end up with a minimal example that looks like the code linked here, but it does not work as it should. In the linked version, my_api_hello_impl() is not called as it should. Also, there is no crash checking the value of the extern symbol api_hello_ptr() when the library is not linked.
my_api.c
#include "my_api.h"
#include <stdio.h>
void(*api_hello_ptr)();
void api_hello_impl()
{
printf("Hello\n");
}
__attribute__((constructor))
static void init()
{
printf("linked\n");
api_hello_ptr = api_hello_impl;
}
my_api.h
#pragma once
extern void(*api_hello_ptr)();
inline void api_hello() { if(api_hello_ptr) api_hello_ptr(); }
some_process.c
#include "my_api.h"
int main()
{
// NOOPS of not linked at runtime
api_hello();
}
Makefile
# my_api is not linked to some_process
some_process: some_process.c my_api.h
$(CC) -o $# $<
my_api.so: my_api.c my_api.h
$(CC) -shared -fPIC -o $# $<
test_linked: some_process my_api.so
LD_PRELOAD="$(shell pwd)/my_api.so" ./some_process
test_unlinked: some_process my_api.so
./some_process
.PHONY: test_linked test_unlinked
Output:
$ make test_linked
LD_PRELOAD="/tmp/tmp.EkrQbILrNg/my_api.so" ./some_process
linked
$ make test_unlinked
./some_process
Does a process checks that the dynamic library he is linking to is loaded when he starts
Yes, it does. If a dynamic library is linked, then it is a runtime requirement and the system loader will not start execution of a program without finding and loading the library first. There are mechanisms for delayed-loading, but it is not the norm on Linux, they are done manually or using custom libraries. By default, all dynamically linked objects need to be loaded before execution starts.
Note: I'm assuming we are talking about ELF executables here since we are on Linux.
How to implement this on Linux?
You can do it using macros or wrapper functions, plus libdl (link with -ldl), with dlopen() + dlsym(). Basically, in each one of those wrappers, the first thing you do is check if the library was already loaded, and if not, load it. Then, find and call the needed symbol.
Something like this:
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
static void *libfoo_handle = NULL;
static int (*libfoo_func_a)(int, int);
static void load_libfoo_if_needed(void) {
if (!libfoo_handle) {
// Without "/" in the path, this will look in all standard system
// dynamic library directories.
libfoo_handle = dlopen("libfoo.so", RTLD_LAZY | RTLD_GLOBAL);
if (!libfoo_handle) {
perror("failed to load libfoo.so");
_exit(1);
}
// Optionally use dlsym() here to initialize a set of global
// function pointers, so that you don't have to do it later.
void *tmp = dlsym(libfoo_handle, "func_a");
if (!tmp) {
perror("no symbol func_a in libfoo.so");
_exit(1);
}
*((void**)&libfoo_func_a) = tmp;
}
}
int wrapper_libfoo_func_a(int a, int b) {
load_libfoo_if_needed();
return libfoo_func_a(a, b);
}
// And so on for every function you need. You could use macros as well.
How to implement this in a cross-platform way (Windows, Mac, Linux)?
For macOS, you should have dlopen() and dlsym() just like in Linux.
Not sure how to exactly do this on Windows, but I know there is LoadLibrary() available in different flavors (e.g. one, two, etc.), which should be more or less the equivalent of dlopen() and GetProcAddress(), which should be the equivalent of dlsym().
See also: Loading a library dynamically in Linux or OSX?

How can I use wasm-bindgen from a program compiled with Emscripten?

I am trying to link a Rust library containing code generated by wasm-bindgen against a program written in C which I would like to compile with Emscripten. My MRE is as follows:
On the Rust side, I have Cargo.toml:
[package]
name = "rust_project"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[dependencies]
wasm-bindgen="0.2"
and in lib.rs I have:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[no_mangle]
pub extern "C" fn call_from_c() {
log("Hello, World!");
}
As a first step, I compile this with cargo build --target wasm32-unknown-unknown which produces a librust_project.a. I then set up the following C project with main.c:
/* forward declare the function from Rust */
void call_from_c();
/* call the function from main */
int main() {
call_from_c();
return 0;
}
and CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(c_project)
add_executable(c_project main.c)
target_link_libraries(c_project /path/to/librust_project.a)
Finally, I attempt to put it all together using the Emscripten toolchain as follows:
cmake -DCMAKE_TOOLCHAIN_FILE=path/to/Emscripten.cmake ../
make
Which is where something appears to go wrong at the linking stage with emcc reporting that __wbg_log_941ab916ed5a24bd is an undefined symbol. I suspect that this symbol (among others) is being stripped out as part of an optimization effort but I am not sure at what stage or how I can disable this optimization.
Adding the following linker options in CMake results in compilation with a warning about the undefined symbol:
target_link_libraries(c_project
path/to/librust_project.a
"-s EXPORTED_FUNCTIONS=[\"_main\",\"___wbg_log_941ab916ed5a24bd\"]"
"-s ERROR_ON_UNDEFINED_SYMBOLS=0")
but I believe these missing symbols are problematic and when I run wasm-bindgen (the CLI tool) over c_project.wasm I get the following error:
import of `__wbg_log_941ab916ed5a24bd` doesn't have an adapter listed
How can I prevent the wasm-bindgen imported/exported functions from being stripped during this process?
This is a work-in-progress answer, which hopefully I will be able to turn into a complete answer in the near future. If not perhaps, it will at least serve as a starting point for others who have come down this path.
I have been working on making my MWE even more minimal by removing CMake and Emscripten and just compiling with Clang directly. This is sufficient since I don't need to worry about the standard library in this MWE.
My command for compiling then becomes:
clang -Wall --target=wasm32-unknown-unknown --no-standard-libraries \
-Wl,--export-all \
-Wl,--no-entry \
-Wl,-L/path/to/librust_project_a
-Wl,-lrust_project
-o main.wasm main.c
Worthwhile noting is that I can trigger the following wasm-bindgen error by adding/removing the --export-all linker argument. Suggesting that the LLVM linker was responsible for removing this section before it could be processed with wasm-bindgen.
import of `__wbg_log_941ab916ed5a24bd` doesn't have an adapter listed

How to mock functions in headerfiles?

What I am doing:
I am using cmocka to run unit tests for large embedded project.
The embedded project is compiled with a arm-gcc-compiler.
The unit tests are compiled with the normal gcc using fragments of the embedded code and the cmocka library.
Normally cmocka recommends to use the -Wl,--wrap=functionName flag to mock (replace) some unneeded sub-functions. This works pretty good.
The Problem:
Well, within my embedded code there is one header file (foo.h), which contains some functions (declared as inline). One of these functions contains some assembler code for the arm-gcc-compiler, which, of course, cannot be compiled by the gcc.
Stupidly the wrap-flag seems not to work on functions which are placed in header files.
Question:
How to mock this function in the headerfile away?
How I tried to solve the Problem:
I thought about inserting some #idef macros to exclude the mentioned assembler section. But this cannot be done because this file belongs to a licensed library and I am not allowed to change its content.
I could extract my function-under-test into an additional files so that foo.h doesn't need to be included anymore. But this would confuse the embedded source codes structure.
Exact lines of problem
The exact code is placed in portmacro.h of freeRtos at line 233:
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
where as portFORCE_INLINE is defined as:
#define portFORCE_INLINE inline __attribute__(( always_inline))
Stupidly the wrap-flag seems not to work on functions
which are placed in header files.
It's not the fault of wrap, the function has been inlined by compiler so there's nothing linker can do.
How to mock this function in the headerfile away?
One option is to use sed to automatically patch the offending code before passing it to gcc. E.g. to change
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
...
}
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void )
{
uint32_t ulNewBASEPRI;
...
}
from your example to
portFORCE_INLINE static void vPortRaiseBASEPRI( void );
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void );
do
cat tmp.c | sed '/inline\|INLINE/,/^}$/{ s/^\(.*\(inline\|INLINE\).*\)/\1;/; /inline\|INLINE/!d }'
The regex is quite sloppy, it relies on the fact that all definitions in header will have the INLINE marker but should probably be enough in your case.
You can embed above command into your Makefile to generate custom header in a temp folder and then override default header with -Ipath/to/temp/folder flag.
I've not used cmocka so I'm unsure if there is a method for managing this already within the framework.
However, cmock uses a method whereby the header is copied to a location somewhere higher in the include hierarchy of the test build (and only the test build, the location is not included even implicitly by the release build).
The copy of this header then can be edited such that the function declaration simply becomes port void vPortRaiseBASEPRI( void );. Then when the mocks are generated a mock is generated for this (and the other function declarations within the same header) just like in any other case. Because hte mocks are being generated it does not matter that there is no matching source code definition (i.e. .c file) for the function(s).
See the "Dealing with compiler-specific stuff" section at https://dmitryfrank.com/articles/unit_testing_embedded_c_applications
And my similar question and how I solved it here: Unit test C with compiler specific keywords

Mocking C functions in MSVC (Visual Studio)

I am reading several articles on mocking C functions (like CMock, or CMocka), but I am not sure how the actual functions are replaced with mocked functions in this process. For example, CMocka relies on automatic wrapping using a GNU compiler, which supports parameters like --wrap to append the __wrap prefix to function calls, or weak symbols which allow you to override any symbol you like.
But how do you do this in Visual Studio, for pretty much all other frameworks?
For example, CMock has an example similar to this (simplified a lot here):
// myfunc.c
#include <parsestuff.h>
// this is the function we would like to test
int MyFunc(char* Command)
{
// this is the call to the function we will mock
return ParseStuff(Command);
}
There is also the actual implementation, which contains the actual function the linker should find in the actual application:
// parsestuff.c
int ParseStuff(char* cmd)
{
// do some actual work
return 42;
}
Now, during testing the Ruby script creates mock functions like:
// MockParseStuff.c (auto created by cmock)
int ParseStuff(char* Cmd);
void ParseStuff_ExpectAndReturn(char* Cmd, int toReturn);
But if the VS project already includes parsestuff.c, how will it be possible that the call from myfunc.c ends up in MockParseStuff.c?
Does this mean I cannot have parsestuff.c included in the unit testing project? But if this is the case, then it's also impossible to mock, for example, MyFunc from myfunc.c in any tests, since I already had to include the file it in order to test it?
(Update) I am also aware that I can include the .c file instead of the .h file, and then do some preprocessor stuff to replace the original call, like:
// replace ParseStuff with ParseStuff_wrap
#define ParseStuff ParseStuff_wrap
// include the source instead of the header
#include <myfunc.c>
#undef ParseStuff
int ParseStuff_wrap(char* cmd)
{
// this will get called from MyFunc,
// which is now statically included
}
but this seems like a lot of plumbing, and I don't even see it mentioned anywhere.
Here's a simple and short solution with hippomocks:
I created an empty Win32 console application with
main.cpp
myfunc.c + myfunc.h
parsestuff.c, parsestuff.h
and added the code from your example.
With help of hippomocks, you can mock every C-Function. Here's how my main.cpp looks like:
#include "stdafx.h"
#include "myfunc.h"
#include "hippomocks.h"
extern "C" int ParseStuff(char* cmd);
int _tmain(int argc, _TCHAR* argv[])
{
MockRepository mocks;
mocks.ExpectCallFunc(ParseStuff).Return(4711);
char buf[10] = "";
int result = MyFunc(buf);
return result; //assert result is 4711
}
HippoMocks is a free, simple and very powerful one-header framework and can be downloaded on GitHub.
Hope I've earned the bounty :)
UPDATE, How it works:
HippoMocks gets the func pointer to ParseStuff
HippoMocks builds a replacement func pointer to a template function with same signature and own implementation.
Hippomocks patches the jmp opcode from the function call prologue in memory, so that it points to the replaced function.
Replacement and memory patch are released after call or in destructor.
Here's how it looks like on my machine:
#ILT+3080(_ParseStuff):
00D21C0D jmp HippoMocks::mockFuncs<char,int>::static_expectation1<0,char *> (0D21DB1h)
If you watch the memory address 00D21C0D (may differ from run to run) in memory window, you will see, that it gets patched after the call of ExpectCallFunc.
I have not dealt with the C mocking libraries or Visual Studio, but I have thought about this in my own project. The Feathers book suggests the preprocessor seam or the link seam as a tool for dealing with this. You already mentioned the preprocessor seam, so I'll focus on the link seam.
The link seam requires the mocked function to be in a library, and the mock function to be in a library. The test can link against the mock function library while the target application can link against the original library.
Of course, as you mention, to mock MyFunc() you will have to create another library and a separate test application to link against it (or dynamically load and unload libraries in the test application).
It sounds quite laborious which is why I am procrastinating adding tests in my own application!
Hope this helps!

Using Go code in an existing C project

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.
The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)
Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.
However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)
I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?
The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke
Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"
To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
func main() {}
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):
...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...
So that's enough to call the exported function. We can write a simple C program that calls it like so:
#include "foo.h"
int main(int argc, char **argv) {
PrintInt(42);
return 0;
}
We can compile it with a command like:
gcc -pthread foo.c foo.a -o foo
The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.
The code above work just fine, but gcc will complain about functions and headers.
The includes should be:
#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"
If you forget the #define _GNU_SOURCE, the gcc will complain:
warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]
If you forget the #include "mygopkg.h", the gcc will complain:
warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]
The last but not less important. The build command line I recommend for production code is:
go build -ldflags "-s -w" -buildmode c-archive -o mygopkg.a
It'll save you 53% size of final mygopkg.a.

Resources