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.
Related
I'm making a CMake project on MacOS, and my project requires libraylib.a and multiple different frameworks. This is what I have:
cmake_minimum_required(VERSION 3.10)
project(RaylibHW)
# Adding executable
add_executable(rlhw my_app.c)
#linking C archives
# Linking frameworks
if(APPLE)
add_library(libraylib STATIC libraylib.a)
target_link_libraries(rlhw PRIVATE
"-framework CoreVideo"
"-framework IOKit"
"-framework Cocoa"
"-framework GLUT"
"-framework OpenGL"
)
endif()
I can link either the frameworks or the archive file, but since apparently it's doesn't work to use target_link_libraries more than once, I can't seem to do it.
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.
I am brand new to C programming (but not programming) and am trying to understand how libraries and header files work together, particularly with respect to packaging and distribution.
After reading this excellent question and its answer, I understand that the header file(s) act as the API to a library, exposing capabilities to the outside world; and that the library itself is the implementation of those capabilities.
However one thing that I cannot seem to find a good explanation of is: how are header files packaged into or distributed with the libraries?
Are the libs and their headers packaged into an archive (zip, tarball, etc.)?
Are headers compiled into libs and distributed alongside them?
When I do a #include "mylib.h", how does the linker know where to find:
the header file itself, mylib.h
the library implementing the functions declared in mylib.h.
how does the linker know where to find: (1) the header file itself, mylib.h
With a notation like #include <mylib.h>, it searches the header file in the system defined include PATH.
With a notation like #include "mylib.h", it searches the header file in the system defined include PATH and in the current directory.
if the header file is present in some other hierarchy, you can provide the path to get the header file with -I option with gcc.
(2) the library implementing mylib.h?
You need to provide the path to the library using -L (in case of non-standard path to the library) and link the library using -l option.
As per the convention, if the (shared) library is named libmylib.so, you can use -lmylib to link to that directory.
For example , consider the pow() function.
It is prototyped in math.h, so in your source file, you need to add #include <math.h> to get the function declaration.
Then, at compile (rather, linking) time, you need to link it with the "math" library using -lm to get the function definition.
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.).
I can't link properly to glew.
I have done:
#define GLEW_STATIC
#include "glew/glew.h"
#pragma comment(lib, "glew/glew32s.lib")
However, I still get the error:
LNK2019: unresolved external symbol __glewGenBuffersARB referenced in function initialize
Save yourself a lot of trouble and just put the glew.c file into your project. I never bother with linking to a glew library externally. Once you have that in there, the GLEW_STATIC macro will work. It's only one file, and (if this matters to you) it will carry nicely across platforms (rather than having to rebuild several OS-specific libs).
I want to extend the excellent #TheBuzzSaw's idea by providing a more detailed answer for a cmake project.
Download GLEW sources from here.
Unzip the archive and copy two files (src/glew.c and include/GL/glew.h) into your project's directory.
Edit glew.c so that the beginning of the file looks like this:
#ifndef GLEW_INCLUDE
#include "glew.h" /* Point to local glew.h file. */
#else
#include GLEW_INCLUDE
#endif
Use the following in your main.cpp file to include static GLEW correctly:
#define GLEW_STATIC
#include "glew.h"
To build the project, you must compile and link the static GLEW library. Sample CMakeLists.txt file with the use of copied files:
cmake_minimum_required(VERSION 3.17)
project(your-project-name)
add_library(STATIC_GLEW glew.c)
add_executable(your-project-name main.cpp)
target_link_libraries(your-project-name STATIC_GLEW)
Now, you should be able to build your project without any linking errors 🎉