Create a static library in C using CMAKE - c

The structure of my project is like this:
DriverFolder
Src
"myDriver.c"
Inc
"myDriver.h"
ApplicationFolder
Src
"myApplication.c"
Inc
"myApplication.h"
The "myApplication.c" source file contains this code:
#include "myApplication.h"
#include "myDriver.h" // Driver included from DriverFolder
uint8_t myFunction(void)
{
uint8_t fooValue = getValueFromDriver(); // A function in myDriver.h
return fooValue;
}
The header file "myApplication.h" contains macros and prototypes
#ifndef LIBRARY_MYAPPLICATION_H
#define LIBRARY_MYAPPLICATION_H
uint8_t myFunction(void);
#endif
I want to create a static library (.lib) using CMAKE. My goal is to include this library in another project. The other project looks like this:
#include "myApplication.h"
int main(void)
{
printf("%d", myFunction());
return 0;
}
I would like to know how to prepare the CMakeLists.txt. For now, this is what I have:
cmake_minimum_required(VERSION 3.0.0)
project(MYAPPLICATION VERSION 0.1.0)
add_library(MYAPPLICATION STATIC myDriver.c myApplication.c)
How to add include paths (DriverFolder/Inc and ApplicationFolder/Inc ?
What else should I add/modify in CMakeLists.txt in order to generate the library?

A static library is really nothing more than an archive of object files. As such they don't contain header files in themselves. Instead when you distribute or install the library, you need to also distribute or install the public header files. What you don't need is to list the header files when creating the actual library, so you don't need to add them at all.
Also, if the object files created from the listed source files (myDriver.c and myApplication.c) are all you need for the actual static library, then the shown CMakeLists.txt file is all that's needed to generate the library.
As mentioned in a comment, there are actually a couple of things missing to help build the object files needed for the library. The creation of the static library itself from the object files is fine.
The problem is that your header-files are in a non-standard location and that the compilers pre-processor will not be able to find the ones not in the same directory as the source file.
That means you have to tell CMake to add flags that tells the compiler where the header files are located. You can do this with the target_include_directories command.
And you also need to list the full (relative) path to the source file.
So the CMakeLists.txt file should probably look something like this:
cmake_minimum_required(VERSION 3.0.0)
project(MYAPPLICATION VERSION 0.1.0)
add_library(MYAPPLICATION STATIC DriverFolder/Src/myDriver.c ApplicationFolder/Src/myApplication.c)
# Tell CMake where the header files are located
target_include_directories(MYAPPLICATION PUBLIC DriverFolder/Inc ApplicationFolder/Inc)
Note that this only makes it possible to build the source files into object files. It will not include the header files inside the library, or automatically install them anywhere.

Related

How to build static library from header-only library

I am trying to build static library of project stb, so I can link it in another project (not written in C/C++).
I have created CMakeLists.txt file to build it using CMake, however the built static library file is empty.
I am suspecting this is due to fact that the stb seems to be header-only library. I tried setting the LIBRARY_HEADER_ONLY flag with target_compile_definitions, this however did not solve my problem.
How can I build header-only library to static library file (*.a)? Or is it even possible? If not, what are workarounds if any?
This is my CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(stb C)
set(MAKE_GENERATOR_PLATFORM x64)
set(CMAKE_C_FLAGS -m64)
set(CMAKE_CXX_FLAGS -m64)
option(STB_IMAGE_IMPLEMENTATION "stb_image implementation" ON)
if(STB_IMAGE_IMPLEMENTATION)
add_definitions(-DSTB_IMAGE_IMPLEMENTATION)
endif()
option(POSITION_INDEPENDENT_LIB "Use position independent code for static library (if applicable)" ON)
set(SOURCE_FILES stb_image.h stb_truetype.h stb_dxt.h)
add_library(stb_static STATIC ${SOURCE_FILES})
target_compile_definitions(stb_static PUBLIC LIBRARY_HEADER_ONLY)
set_target_properties(stb_static PROPERTIES LINKER_LANGUAGE C)
set_target_properties(stb_static PROPERTIES
OUTPUT_NAME stb
POSITION_INDEPENDENT_CODE ${POSITION_INDEPENDENT_LIB})
To get an object files and build a static library from the header-only library the extra .c file must exists. This is because .c files are the ones which contains instructions and code.
Different toolchains may interpret .h file differently so the easy and portable way to create the implementation is to create a new .c file.
#define STB_IMAGE_IMPLEMENTATION
#define STB_DXT_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_dxt.h"
#include "stb_truetype.h"
Including the header files (stb_image.h) and defining the requried macros (STB_IMAGE_IMPLEMENTATION) in the .c file is the solution to get object files and static library (with proper content) out of the build.

How to organize header files in a library

Say I am writing a small libary in C, with most of the source code in two folders src/A and src/B, and where the header file src/A/a.h needs to include src/B/b.h. When writing code for a non-library project, I usually write
#include "B/b.h"
in a.h and use the -Isrc flag to tell the compiler where to look for header files.
Now suppose that my library is installed locally at ~/mylib and that I want to use functions from a.h from a different project. Simply including that file using
#include "~/mylib/src/A/a.h"
would not work, because ~/mylib/src/B/b.h might not be part in the search path. My question is about the canonical way to solve this issue. It's probably quite basic, but I haven't done any advanced programming in C and have been unsuccessful in my attemps to find a solution online.
Possible solutions I thought of are the following:
Add ~/mylib to the search path, but that might lead to problems if the library and client projects have header files with the same name (say src/helpers.h). Is it possible to include one header file without cluttering the search space with files I won't need?
Use relative paths in the library header files, but that doesn't feel very robust.
Thank you.
The normal approach is to have a separate directory specifically for the headers which form the public interface of your library. Usually this directory would be called 'include'.
You would then place the public headers for your library under a library-specific directory in there, i.e. "mylib/include/mylib/b.h". This extra 'mylib' directory prevents clashes if you're using some other library that also has a "b.h". You can also, if you wish, keep other private headers, which do not form the public interface of your library, under the 'src' directory instead, to stop them being exposed to users of the library.
This means a user of the library can then use "-I mylib/include" to include this directory, and include the individual files with, for example, "#include "mylib/b.h".
Why aren't you using the standard implementation? Break out into header and source files into their own directories. Add #define headers to avoid multiple includes or namespace corruption.
Here is your directory structure:
~/mylib/headers/a.h
b.h
~/mylib/src/a.c
b.c
Now a.h will have at the very top of the file...
#ifndef __A_H__
#define __A_H__
// code
#include "~/mylib/headers/b.h"
// end of file
#endif
Now b.h will have at the very top of the file...
#ifndef __B_H__
#define __B_H__
// code
// end of file
#endif
Then just compile. gcc -I~/mylib/headers
If you have 2 helpers.h just change the #define __HELPERS_H__ in one of the files to something else like #define __HELPERS2_H__

Remove precompiler directive from .h header file

I'm facing a problem that I don't know how to solve.
Suppose the following typedef struct into a test.h header file:
typedef struct example_struct {
#ifdef CONFIG_A
int A;
#endif;
int B;
} example_struct_t;
I am compiling the code using this header file passing CONFIG_A to the GCC with -D option. This way I am able to include A member to the struct or remove if not needed for a given use case.
Now suppose I generate a shared library (.so) and I would like to distribute it. So, I have the .so library and the headers with precompiler directives. The problem is that I would like not to include the -DCONFIG_A in the program using the library, I mean, I would need to hold the options employed at the library compilation time not only in the source files (.c) but also in the header. That is to say, if a compile the library with -DCONFIG_A option I suppose that program using the library shouldn't include that option in compilation time.
Are the precompiled headers the solution for this problem or is there any other alternative (avoiding include a config.h header in every files defining precompiler directives)?
Thank you so much for the guidance.
You can "generate" the code for the structure definition and ship the generated definition alongside the corresponding library. One idea is to keep your structures in a header with no #includes, in which case you can run the C preprocessor on them to get a file with no #ifdefs (which you can then use to build and ship).
Another way is to do something special in your build system. For example CMake has #cmakedefine which you can use inside a C or C++ source file and then generate code from that.

Setting up a C project with multiple source files in MPLAB

I'm using the MPLAB IDE and the XC8 compiler for a C project for PIC18 devices. I'm building a project with multiple source files and don't know how to make the structure.
In the project, I have the following things:
A file main.c where the main code is located. From here, several files are included:
xc.h: to define chip-specific variables and so
stdlib.h, stdio.h, plib.h, delays.h: for the compiler's functions
enc28j60.h: a homebrew file with definitions and prototypes
A file enc28j60.c, where the functions of the prototypes in enc28j60.h go
I cannot compile enc28j60.c as standalone file because it depends on definitions in main.c.
I have a few questions on how to set this project up:
Should I add enc28j60.c to the source files of my MPLAB project? If I do this, MPLAB tries to compile the file, which fails. If I don't do this, the linker cannot find the symbols that are defined in enc28j60.c and prototyped in enc28j60.h.
Should I #include enc28j60.c from somewhere? If not, how does MPLAB know where to get the file?
Should I add enc28j60.h to the header files of my MPLAB project?
Should I #include enc28j60.h from somewhere? Right now, I do this in main.c, after the definitions enc28j60.h needs in order to run (and not throw #errors).
I managed to get this working by modifying my library and header files a bit.
At first, I added a file main.h where all the prototypes, #defines and #includes would go. Then, in every .h, file, I added this on top:
#ifndef SOME_LIB_IDENTIFIER // makes sure the lib only gets included once,
#define SOME_LIB_IDENTIFIER // has to be specific for every lib
#include "main.h" // to make sure everything's initialized (this line of course not in main.h)
And the last line of every .h file would be:
#endif
I added #include "enc28j60.h" to the top of the enc28j60.c file. This file now can be compiled.
In main.h, I added includes for xc.h, plib.h, stdlib.h, stdio.h and enc28j60.h. I nowhere included .c files.
I added both the main and enc28j60 header and source files to my MPLAB project. The source files get compiled well, both. The result is linked together.
In short
Add a main.h where all prototypes, #defines and #includes go
Add a header and footer to all your header file to make sure they're only included once. Also include main.h from these headers, to make sure every file uses the same definitions
Include a source file's corresponding .h file at the very first line of your source file. Do not include .c files
Add all header and source files (that are not built into the compiler) to your MPLAB project
Build (F10) should compile all files and link them together correctly
Don't include .c files. Include headers only. If you have declarations to be shared between files, put them in a separate header, and include that header whenever you need it.
After compiling each individual source file, link the resulting object files together. This involves the invocation of the compiler on all of the source files, then a one-time invocation of the linker on the object files (with supplemental libraries, etc.).

Linking to MATLAB generated code

I'm using embedded MATLAB to generate C code from an .m script. However, after the generation I'm left with about 15 files (most of them are source). If I want to write a standalone main in C how do I link to the MATLAB generated code? Is there a way to do this without writing my own Makefile?
So I figured out how to generate static libraries (.a) with the matlab generated code... can I build dynamically loaded libraries (.so)?
I don't know if this is particular to my project, but I find that I can include Matlab generated files the same way as you would normally include anything else.
I copy my generated matlab source files (.c and .h) into my project directly, and then I have to specifically add them to my project. ( I wonder if that has more to do with the IDE I use though).
Then, in main.c that you create, just add the line #include "yourGeneratedFile.h". Within main.c now, you should be able to use whatever functions were created by Matlab.
For instance, in an example:
within main.c, include the header file and use the function you need
#include "SPIUARTDemo30f.h"
//further down in the file
SPIUARTDemo30f_step(); //using the function I asked Matlab to generate
SPIUARTDemo30f.h and SPIUARTDemo30f.c are the generated files from Matlab:
within the .h you'll see
extern void SPIUARTDemo30f_step(void);
and, if you look at the .c you'll find:
void SPIUARTDemo30f_step(void)
{
/* lots of code */
}

Resources