CMake building a static library with other static library - cmake

My problem is as follows :
I have OpenSSL as static libraries (libcrypto.a and libssl.a).
Compiled on Windows with MSys2/MinGW64.
Besides that, I have a small self written library based on OpenSSL.
Now I want to "bundle" the Crypto lib from OpenSSL with My lib to a "big" static library for later statically compiling in other applications on Windows without deploying any library.
What would a CMakeLists.txt file looks like? And are the prerequisites (OpenSSL as static libs) correct?
Actually compiling this to a dynamic DLL works like a charm. But My static lib are only includes the symbols of My own library, not from OpenSSL too.
Actually I have no working CMake file, so I can't include an example. I'm just looking for a direction how to do it.
A short suggestion how to begin would be highly appreciated.

If what you really want to do is combine multiple static libraries into one, for the convenience of external consumers, you'll probably need to run a custom command to do this (as it's not something that's frequently done).
Using the GNU toolchain, the commands to do so might look something like this (untested though):
${CMAKE_COMMAND} -E make_directory tempdir
cd tempdir
${CMAKE_AR} x $<yourlib:TARGET_FILE>
${CMAKE_AR} x ${OPENSSL_CRYPTO_LIBRARY}
${CMAKE_AR} x ${OPENSSL_SSL_LIBRARY}
${CMAKE_AR} cf ${CMAKE_BINARY_DIR}/bin/libyourmegalib.a *.o
cd ..
${CMAKE_COMMAND} -E remove_directory tempdir
Then you would use add_custom_command() to create a target to run this script - either put those lines as COMMAND arguments, or create a script template, substitute values at CMake generation time using configure_file(), then have the custom command run that script.
That said, if the external consumers are all using CMake themselves, I would skip this entirely, and just have the installation process for your library generate CMake package configuration files that declare the dependencies on the OpenSSL libraries.

target_link_library() works both for add_executable() and add_library(), so you should be able to do:
add_library(yourlib STATIC ...)
target_link_libraries(yourlib lib1 lib2 ...)
(where yourlib is your library, and lib1, ... are the libraries you want to bundle.

Related

CMAKE - makefile target for a library

I'm currently changing the build system on my project, from gnu makefiles to cmake (that generate makefiles).
My project generates several libraries (.lib), and several executables (.exe).
Currently i generate the makefiles using the following command :
cmake -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Debug
The generated makefiles contain an all target, as well as a target for every executable (compiled as such with the add_executable cmake directive), so i can compile a subset of the project (which saves a lot of time) : make executable_1; make executable_2 and so on.
However, there is no target for the libraries (compiled as such with the add_library cmake directive) so i cannot do make library_1 for example. I want to do this because it would save a lot of time.
I tried to add a dummy executable in the library's cmake, and link the library to this executable (which only contains a main without actually using library_1's code).
add_library(library_1 test.cpp)
add_executable(dummy_exe dummy_main.cpp)
target_link_library(dummy_exe library_1)
It does add a target for dummy_exe but does not build the library because it does not actually need to link any of the library_1's code.
This was a workaround attempt anyway, and i'd rather just call make library_1 after all. Is there any way to add a makefile target for a library using cmake ?
As answered by w-m and Fred, CMAKE indeed create a target for libraries in the Makefile.
I was trying to build the library with the cmake subproject name of the library instead of the library name.
make help was indeed of big help to find this issue, as it lists everything that can be built.

How to add and use a resource in C99 project with CMake that is portable?

I am trying to create a CMake C99 project that will have an embedded resource that can be read by the project. And this project should be portable. I am actually using CLion but I think this is a just CMake question.
Ideally I would like to see a simply way to embed helloworld.txt file in the CMake project and then a way to read the contents into const char* helloword_txt = ?? variable. And then have this compile with GCC or a Microsoft C++ compiler.
I have looked at the CMakeRC.cmake project but that look like a C++ specific way. I looked at commands like ld -r -b binary -o binary.o foo.bar # then link in binary.o but that look like Linux-specific way.
I thought CMake was designed for portable projects. Is there a portable way to do this?
I doubt there is a independent resource management system available. At least, I don't know of any.
You can take a look at Qt's qrc - it is more or less portable, but introduce a Qt dependency, of course.
First I would use FILE *fopen( const char *restrict filename, const char *restrict mode ) from C99 Standard.
Then in CMake I would use install(FILES helloworld.txt DESTINATION ${CMAKE_INSTALL_BINDIR})
note: CMAKE_INSTALL_BINDIR comes from GNUInstallDirs built-in module.
Then using a bash/bat script you can always run the program from the "BIN_DIR" so the path to helloworld.txt is "."
e.g. add_executable(foo_prg ...) ... install(TARGETS foo_prg ...)
/usr/bin/foo:
#!/usr/bin/env bash
cd /usr/bin && ./foo_prg
So user can run ./foo which will "trampoline" to /usr/bin to run foo_prg binary
Note: To test without installing, you can add to CMake:
file(COPY helloworld.txt DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
note: does not work for multi-configuration build but should be easy to deduce.
note2: don't know (i.e. never tested) if we can use $<TARGET_PROPERTY:foo_prg,RUNTIME_OUTPUT_DIRECTORY> instead.

Creating a library in CMake depending on source files not available when generating build files

I have a CMake configuration file building two libraries:
a third-party library (here called ThirdPartyLib) containing a real-time OS / board support package from a supplier. It is built outside CMake using the autotools toolchain.
an extended version of the former library (here called ExtendedThirdPartyLib)
Unfortunately, some source code that I need (various tools) are not built in the ordinary build script for (1). Since I don't want to mess with the suppliers build script I want to add another library (2), building the missing files and thus extending the library from the supplier.
I want to able to do something like this in CMakeFiles.txt:
cmake_minimum_required(VERSION 3.2)
project(bsp)
include(ExternalProject)
ExternalProject_Add(
ThirdPartyLib
URL <http://some.url/bsp.tar.bz2
BUILD_COMMAND make -C ../external/ThirdPartyLib/src
)
set_target_properties(ThirdPartyLib PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_library(ExtendedThirdPartyLib
${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file1.c
${CMAKE_CURRENT_BINARY_DIR}/some/path/missing_file2.c
)
add_dependencies(ExtendedThirdPartyLib ThirdPartyLib)
target_include_directories(ExtendedThirdPartyLib PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/some/path/include
)
target_link_libraries(ExtendedThirdPartyLib ThirdPartyLib)
The problem here is that the path to missing_file1.c and missing_file2.c are not valid when CMake is generating the build files (they are extracted from the tarball from the supplier). CMake exits with an error output saying: "Cannot find source file".
Is there a neat way to make this work? I.e. is it possible to convince CMake that certain non-existant input files will exist when building of the library begins? Or is there any other recommended way to solve this issue?
(I have temporary made local copies of the files I need to build from the suppliers tarball, but that is of course not a good solution. If those files are changed in future versions of the suppliers package and I forget to overwrite my local copies it could be a horrible mess...
Another "solution" would be to create a small makefile outside CMake and use another ExternalProject_Add in the CMakeFiles.txt somehow. But that's not a good solution either, e.g. if compile and linker flags are modified I need to remember to change the makefile too.)
Personally, I dislike the ExternalProject_Add command, because it does way too many things for my taste, but I've digressed.
What if you do something like this, where bar is simulating your ExtendedThirdPartyLib target, since it depends on generated files
cmake_minimum_required(VERSION 3.11)
project(lol C)
set(SOURCES lol.c) # only this file exists
add_library(lol ${SOURCES})
set(FOO_FILES "foo1.c" "foo2.c")
add_custom_command(OUTPUT ${FOO_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Creating ${FOO_FILES}"
VERBATIM)
add_custom_target(foo DEPENDS ${FOO_FILES})
add_library(bar ${FOO_FILES})
add_dependencies(bar foo)
target_link_libraries(lol bar)
The whole approach hinges on the fact that the method, where produced/generated files are procured, is explicitly defined via the custom command and associated custom target.
You should modify the custom command to extract the required files (e.g. could even call some external script) from the tarball (which might require downloading with curl or something similar).

CMake build & link to library without installing to /usr/local or elsewhere

I'm trying to include an external library in a build environment that uses CMake. I'm not trying to install it on the local system (in fact I'd rather not do that, I don't want /usr/local clogged up with all kinds of libraries); I'd just like to have the resulting libxml2.a available for linking with my executable. I can build it fine with the following in CMakeLists.txt:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_target (build_libxml ALL
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
But I'm still having trouble with the following:
1) Is this the right approach in the first place, for the general purpose of getting libraries built with configure and make into a CMake environment?
2) How do I get the resulting library (i.e. libxml2.a) under my build output directory?
3) How can I link to that library for my executable builds?
I tried a fiddly solution with
ADD_LIBRARY( xml2 STATIC libxml2.a )
but it seems like there must be a better way than hauling a whole library's contents into… a library.
Thanks.
You need to make it clearer to CMake what is going on here. All it can see now is that you have some custom command that it will run every time. Instead of using add_custom_target with COMMAND, I've found it better to use add_custom_command.
Something like this:
set (LIBXML_PATH ${MY_SOURCE_DIR}/libxml2-2.9.1)
add_custom_command(
OUTPUT libxml2.a
COMMENT "Building libxml"
COMMAND ./configure --prefix=/tmp
COMMAND make
WORKING_DIRECTORY ${LIBXML_PATH}
)
target_link_libraries(your-program libxml2.a)
By doing it this way, CMake can understand that your custom command's essential product is libxml2.a, and when CMake sees something depending on that, it will run the command (if the library doesn't exist already).

CMake to produce -L<path> -l<lib> link flags for static libraries

I'm using CMake 2.8 in order to build an application based on MQX OS (using CodeWarrior).
The CMake project basically builds a set of static libraries (let's say LIB1 and LIB2).
I then reference these libraries in the final executable cmake rule:
target_add_executable(X ${some_sources})
target_link_libraries(X LIB1 LIB2)
My problem is that some symbols are defined in more that one library.
Thus, a link command like:
mwldarm <args> -o <output> <objects> /path/to1/libLIB1.a /path/to2/libLIB2.a
would lead to multiple definition of symbols error.
Instead, I would like CMake to generate a link command like:
mwldarm <args> -o <output> <objects> -L/path/to1 -L/path/to2 -lLIB -lLIB2
Question: How to get the following variables from CMAKE?
Libraries directories flags (ex: -L/path/to1 -L/path/to2)
Libraries link flags (ex: -lLIB -lLIB2)
I've read stuff concerning RPATH but it seems to concern shared libraries only. Am I right?
Thanks for advance.
I do appreciate.
It seems that policy CMP0003 may be what you need.
To use it add the following line near the beginning of your CMakeLists.txt:
CMAKE_POLICY( SET CMP0003 OLD )
Another possibility is to directly set the dependencies and search path, however it's not the cleanest way. Assuming you libraries are called liba.a and libb.a, then:
LINK_DIRECTORIES( ${paths_to_search_for} )
TARGET_ADD_EXECUTABLE(X ${some_sources} )
ADD_DEPENDENCIES(X LIB1 LIB2)
TARGET_LINK_LIBRARIES(X a b )
Note that in this case a and b are not cmake targets, therefore a little machinery is needed to correctly set the dependencies.
Part of the design of CMake is that it links with full paths. Why is that a problem?
Toggling the behavior with the policy is not the correct approach.
http://www.cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd4fa896b
I think CMP0003 is used to switch on/off the function of adding searching path automatically as described in the official document
Libraries linked via full path no longer produce linker search paths.
rather than about replacing the path name with -l.
When linking a library, if the library is a target CMake known, CMake always replaces related -L and -l options with the library's path name. This may not be a problem for linking static libraries. But for a executable to link a shared library, it's may be a problem. Then I found a hacking method, code like below, to solve the problem linking a shread library using -L and `-l' rather than absolute path.
# Find out the link.txt
set(LINK_TXT "${CMAKE_BINARY_DIR}/${ToLinkLib}/CMakeFiles/${ToLinkLIb}.dir/link.txt")
# Add the searching path into link command
add_custom_command(TARGET ${YourTarget} PRE_BUILD
COMMAND sed ARGS -ie "\"s;[[:blank:]]-l; -L${LIBRARY_OUTPUT_PATH} -l;\"" ${LINK_TXT}
DEPENDS ${LINK_TXT}
COMMENT "Hacking CMake: edit __link.txt__ to use -l instead of path to link internal library ...")
# NOTE: Dont't missing the `-l'.
target_link_libraries(${YourTarget} -l${ToLinkLib})
Of course, this is just a hacking so may not be working well with all versions of CMake.
UPDATED: why linking a shared library may be a problem?
When I run a executable cross compiled for android, which linking a shared library built by the same CMake scripts, I've encounter a problem of linking failed. After I used the above hacking method to get a new version, I can run my executable with a command like below
$ LD_LIBRARY_PATH=. ./the_exe opts