Create a static library that refers to other static libraries - static

I would like to create a static library that depends on another library, in this case ZLIB, for which I already have a static build (libz.a).
I have the following:
...
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
set (BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set (CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) # to find the .a instead of the .so
...
find_package(ZLIB REQUIRED)
if (ZLIB_FOUND)
message(STATUS "ZLIB library: ${ZLIB_LIBRARIES}") # ZLIB library: /usr/lib64/libz.a
include_directories(${ZLIB_INCLUDE_DIRS})
set (EXT_LIBS ${EXT_LIBS} ${ZLIB_LIBRARIES})
endif()
...
add_library (libTest ${MCCORE_SOURCES_CC})
target_link_libraries(libTest ${EXT_LIBS}) #EXT_LIBS = /usr/lib64/libz.a
However, the final step of the build is creating the static library but without any reference to /usr/lib64/libz.a
ex:
/usr/bin/ar cr libTest.a object1.o object2.o ... objectN.o
I would expect:
/usr/bin/ar cr libTest.a object1.o object2.o ... objectN.o /usr/lib64/libz.a
It seems the final archive creation doesn't care for libraries set with target_link_libraries.
Any ideas?
What can I do to force this?

Under Windows (with Visual Studio) the following would do the trick:
add_library(fooStatic1 STATIC fooStatic.cpp)
set(LIBS_TO_COMBINE "${CMAKE_BINARY_DIR}/libfooStatic1.lib ${ZLIB_LIBRARIES}")
add_library(combined STATIC ${LIBS_TO_COMBINE} dummy.cpp) #dummy.cpp being empty
add_dependencies(combined fooStatic1)
set_source_files_properties(${LIBS_TO_COMBINE} PROPERTIES EXTERNAL_OBJECT TRUE GENERATED TRUE)
set_target_properties(combined PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(combined PROPERTIES STATIC_LIBRARY_FLAGS "${LIBS_TO_COMBINE}")
Unfortunately, it won't work under linux, as ar will just combine the archive files without unpacking them - creating something that is not really usable. In order to achieve your goal you need to extract the .o files and recombine them:
ar -x /usr/lib64/libz.a
ar -x libfooStatic1.a
ar -rc libcombined.a *.o
I am not aware of a CMake macro that would help in the process. You could probably run ar -x in execute_process(...), glob the output, and then run ar -rc.

Related

Compile asm file with c files using cmake

I need to compile a static library composed by c files and one asm file using CMake. In the lib dir I have a CMakeLists.txt similar to the following:
I have moved the
set(CMAKE_ASM_COMPILER nasm)
in an upper cmake list and modified de inner
enable_language(C ASM)
include(sourcelist)
add_library(myLib ${sources} foo.asm)
set_property( SOURCE ${sources} APPEND PROPERTY
COMPILE_DEFINITIONS "MYDEF1" ;"MYDEF2")
set_source_files_properties(${sources} PROPERTIES COMPILE_FLAGS -fPIC)
set_property(
foo.asm
APPEND
PROPERTY COMPILE_DEFINITIONS
"QNXNTO")
set_source_files_properties(${sources_asm} PROPERTIES COMPILE_FLAGS "-f elf ")
target_include_directories(myLib PRIVATE ../}
where ${sources} are my c files that are compiled correctly, but
when I try to compile the asm file I got
/usr/bin/nasm -DQNXNTO -f elf -o CMakeFiles/mylib.dir/foo.asm.o -c foo.asm
nasm: error: unrecognised option `-c'
So I have the problem with -c option, it should be -s
How can I remove the unwanted "-c" ?
I have solved the issue:
in the outer cmake list set
.....
set(CMAKE_ASM_NASM_COMPILER /usr/bin/nasm)
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS asm)
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf)
.....
the inner one will be modified in the folowing way:
enable_language(C ASM_NASM)
include(sourcelist)
add_library(myLib ${sources} foo.asm)
set_property( SOURCE ${sources} APPEND PROPERTY
COMPILE_DEFINITIONS "MYDEF1" ;"MYDEF2")
set_source_files_properties(${sources} PROPERTIES COMPILE_FLAGS -fPIC)
set_property(
foo.asm
APPEND
PROPERTY COMPILE_DEFINITIONS
"QNXNTO")
target_include_directories(myLib PRIVATE ../}
The output:
/usr/bin/nasm -DQNXNTO -f elf -o CMakeFiles/mylib.dir/foo.asm.o -c foo.asm

How to Export User Defined Library in C

I've created a rather large library:
DataStructures.h :
Stack.h :
Stack.c
LinkedList.h :
LinkedList.c
HashTable.h :
HashTable.c
etc...
How would I export this library so others can use them? Would they have to link the .c together with their main?
You need to compile your .c files into a library and distribute the library and headers together.
There are two types of library; dynamic (ending in .so on Linux) and static (ending in .a on Linux).
I believe static libs end in .lib on Windows and dynamic libs end in .dll over there, but I'm not a windows dev.
Macs can have both .so and .dylib files, depending on your tool chain.
On Linux, the general way to make a static lib is with the tools ar and ranlib. Assuming your Makefile has a list of object files called OBJS,
mylibrary.a: $(OBJS)
ar -ru $# $(OBJS)
ranlib $#
Creating a shared library is similar, but instead of ar and ranlib, you usually use gcc -shared, and you must compile the object files for "position independent code", ie add -fPIC to your CFLAGS.
Once you have the library and the header files, place the headers in a directory called "include" and the library in a directory called "lib". Archive these two directories up (eg with tar or zip) and send them to whoever is using them.
Note that they will need the same kind of computer, operating system version, compiler, etc as you. This is why C library code is most frequently shared in source code format.

How to create one static library from several others static libraries in C on Linux? [duplicate]

This question already has answers here:
How to merge two "ar" static libraries into one?
(9 answers)
Closed 3 years ago.
For example,
we have three following libraries:
1.1.......................lib_A.a
1.2.......................lib_B.a
1.3.......................lib_C.a
Now I want to create one library which consists of all the above static libraries.
I have used following command:
ar -crs lib_Z.a lib_A.a lib_B.a lib_C.a
When I create final executable with lib_Z.a, the compiler gives me the following error:
error adding symbols: archive has no index; run ranlib to add one
How to solve this issue?
Your lib_Z.a contains no object files; it only contains other .a files, and the loader doesn't know how to handle that. Running ranlib wouldn't help; it wouldn't find any object files in the lib_Z.a archive. You have to extract the object files from the separate libraries and then build them all into the result:
mkdir Work
cd Work
ar -x ../lib_A.a
ar -x ../lib_B.a
ar -x ../lib_C.a
ar -crs ../lib_Z.a *.o
cd ..
rm -fr Work
The only trouble you can run into is if two of the libraries contain the same object file name (e.g. lib_A.a contains config.o and so does lib_B.a but they define different configurations). You would have to rename one (or both) of the object files:
…
ar -x ../lib_A.a
mv config.o A_config.o
ar -x ../lib_B.a
mv config.o B_config.o
…

Makefile for a system

I'm trying to build an application where there are two different systems interacting with each other and most of their functionalities are common. So I'm planning a directory structure like this.
Xxx
|_sys1
|
|_sys2
|
|_common
Each have a separate include and src directories.
Learned from a little browsing that keeping the compilation of common as libcmn.so will be efficient and can be linked for compiling xxx and yyy.
Though I understand how to create a .so, using them in a makefile with variables and linking header files are new to me.
Can someone guide me on how the Makefile for each should be and how linking should be done for a proper build?
In a make(1) control file, sequencing is important. Here is the general rule:
Targets placed on the same prerequisites line may be build concurrently. Order is preserved between different <code>Makefile</code> targets. So something like this:
all:: a b
a:: a.o lib/libfoo.so
${CC} ${LDFLAGS} -o $# a.o -Llib -rpath=lib -lfoo.so ${LDLIBS}
b:: b.o lib/libfoo.so
${CC} ${LDFLAGS} -o $# b.o -Llib -rpath=lib -lfoo.so ${LDLIBS}
lib/libfoo.so:
${MAKE} -C lib all
Now, on a big server you can do this:
$ make -j10 all
and everything will be built in the right order. Just be sure there is a Makefile in the lib directory that knows how to build the library.
Unless libfoo.so is significantly large, I'd make it a static libary, then you would not have to pre-program where to find it later at runtime.
To compile xxx and yyy that use your libcmn.so, they just need to include the library interface header.
To link with the library just add a -lcmn and -Lpath/to/your/lib to your LDFLAGS
To be noted that using this method, you will need to :
Add the library path to LD_LIBRARY_PATH
or add the library path to ldconfig
or move the library to a place where ldconfig looks already (/usr/lib for example)
You can also use the dlopen and dlsym functions to map your libcmn functions to function pointers at runtime. This will allow you to specify the path and name of the library to load at runtime and avoid the LD_LIBRARY_PATH problem.
You will need to add the -ldl flag to compile using this technique

CMake: Static and dynamic linking based on BUILD_TYPE

I am developing a small simulation software that depends on two libraries, the GSL and the libconfig. As a build system, I use CMake. For both the GSL and libconfig, I found cmake files and copied them into the cmake/ directory of my project.
The scenario is the following: I want the project to have several different build types, like debug, release, etc., but also a custom one called cluster, which adds -static to the GCC flags and links against the .a libraries of the GSL and the libconfig, which I assume exist.
My CMakeLists.txt looks like this so far:
# version
SET(PACKAGE_VERSION "1.0")
SET(PACKAGE_NAME "INTERFACE")
PROJECT(interface C CXX)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# dirs -----------------------------------------------------
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
FIND_PACKAGE(GSL REQUIRED)
INCLUDE_DIRECTORIES(${GSL_INCLUDE_DIRS})
SET(LIBS ${LIBS} ${GSL_LIBRARIES})
FIND_PACKAGE(LibConfig REQUIRED)
INCLUDE_DIRECTORIES(${LIBCONFIG_INCLUDE_DIRS})
SET(LIBS ${LIBS} ${LIBCONFIG_LIBRARIES})
CONFIGURE_FILE("res/config.h.in" "config.h")
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
SET_DIRECTORY_PROPERTIES(PROPERTIES
ADDITIONAL_MAKE_CLEAN_FILES "config.h"
)
# compilation ----------------------------------------------
ADD_EXECUTABLE( interface
interface.c interface.h config.h
helpers.c
output.c
lattice.c
genetic.c
)
# optional CFLAGS
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -std=c99")
SET(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math")
SET(CMAKE_C_FLAGS_CLUSTER "-O3 -ffast-math -static")
SET(CMAKE_C_FLAGS_DEBUG "-g")
SET(CMAKE_C_FLAGS_PROFILE "-g -ffast-math -pg")
TARGET_LINK_LIBRARIES(interface m ${LIBS})
# installation --------------------------------------------
INSTALL(TARGETS interface DESTINATION bin)
This adds the -static to the compiler, when I use -DCMAKE_BUILD_TYPE=cluster. The thing is, that it still links against the .so versions of the libs, which causes gcc to throw errors. At least the FindLibConfig.cmake scripts sets both a LIBCONFIG_LIBRARY and a LIBCONFIG_STATIC_LIBRARY variable, which I could use.
What is the most elegant or smart way to reach my goal?
Acording to cmake documentation, cmake uses the variable BUILD_SHARED_LIBS to determine the default for add_library().
If you set to ON cmake will assume all add_library() call will be as
add_library(target SHARED lib1 lib2 ...)
For example something like -DBUILD_SHARED_LIBS=ON on the cmake command line may do what you are asking.
I solved it like this:
The User can specify an additional variable -DSTATIC_LINKING=TRUE. Then, the script looks like this. (Only the important parts for the static linking and compilation are shown!)
# determine, whether we want a static binary
SET(STATIC_LINKING FALSE CACHE BOOL "Build a static binary?")
# do we want static libraries?
# When STATIC_LINKING is TRUE, than cmake looks for libraries ending
# with .a. This is for linux only!
IF(STATIC_LINKING)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
ENDIF(STATIC_LINKING)
# set -static, when STATIC_LINKING is TRUE and set LINK_SEARCH_END_STATIC
# to remove the additional -bdynamic from the linker line.
IF(STATIC_LINKING)
SET(CMAKE_EXE_LINKER_FLAGS "-static")
SET_TARGET_PROPERTIES(surface PROPERTIES
LINK_SEARCH_END_STATIC 1)
ENDIF(STATIC_LINKING)

Resources