cmake: using shared library while building when only headers exist - gcc

I would like to
build a binary that is relying on a shared library at runtime.
the library does not exist while compiling the binary.
the headers for the library are available
I would like to create a CMake project under those circumstances. Therefore I tried the following, but it will complain about the missing lib for sure:
cmake_minimum_required (VERSION 3.8)
project (example)
add_executable(${PROJECT_NAME}
main.c
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
# system libs
lib_that_does_not_yet_exist
)
When removing the link instruction to lib_that_does_not_yet_exist, then I will get a undefined reference error.
Question: Is there any way to accomplish what I need?
Background: I am crosscompiling the binary, the lib is therefore having the wrong architecture to install it on the host. I know there may be some ways around that issue, but I am mainly interested in the above question.

Related

CMake + Xcode: how to select arm64 vs x86_64 libraries?

We have a CMake based project targeting Xcode, and must include a precompiled 3rd party library which supplies separate arm64 and x86_64 binaries.
What we have working now is to simply attach both binaries like
add_library( someLib INTERFACE )
add_library( someLib_x64 STATIC IMPORTED )
set_target_properties(
someLib_x64
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/x64/libsomeLib.a"
)
add_library( someLib_arm STATIC IMPORTED )
set_target_properties(
someLib_arm
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/arm/libsomeLib.a"
)
target_link_libraries(
someLib
INTERFACE
someLib_x64
someLib_arm
)
This seems to result in a valid compilation for both architectures (building for "Any Mac (Apple Silicon, Intel)"), however it causes a bunch of linker warnings as each architecture complains about the other one.
ld: warning: ignoring file /path/to/x64/libsomeLib.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
and vice versa.
What is a more accurate way to do this that avoids linker warnings? I couldn't find an applicable generator expression to change the link path?
Edited, I misunderstood this previously. I think you have 3 options
suppress error, the error doesn't affect anything in fact, so the simplist way to
add_link_option("-w")
to ignore it, or just change link option for the target
try the latest cmake concept IMPORTED_TARGET, it looks like perfectly fit your demand, but require new cmake version
try to compile an universal library from source code, this is some example
change flag or cmake official example, but this looks like need another project for source code of the lib
UPDATE: ACCEPTED ANSWER:
Based on the documentation for IMPORTED_TARGET linked here, it revealed that you can use the symbol $(CURRENT_ARCH) in the library path, which is interpreted by Xcode at link time.
Works perfectly.
You can combine the two .a files into the fat binary and use the combined library for compilation. The linker will select the correct version based on the architecture.
To combine the .a library files, you can use the lipo command:
lipo -create 'path/to/x64/libsomeLib.a' 'path/to/arm/libsomeLib.a' \
-output 'path/to/combined/libsomeLib.a'
The combined library file can be reused until you need to install an update to the library. Alternatively, you can create a aggregate target to combine the library files every time you compile if you prefer not to manage the library manually.

gcc auto link shared libraries needed by static libraries

I've installed the Nana library and I've read from their website that the library needs some shared libraries to work.. So during linking (gcc) i need to put all links (-lXft, -l...).
Is there a solution to auto link shared libraries needed by Nana?
I am using ubuntu 18.04 and I've read that I can do that with Makefile but I haven't understood how.. I want to use Premake to organize my project so that I can say to Premake that it needs to include the Nana library and then Premake "smartly" find all shared libraries..
When I used Premake and I linked the Nana library (statically) the compiler gaves me a lot of errors...
all the errors say:
undefined reference to: X...
So I need to include all the shared libraries that Nana needs, but how?
gcc has no idea about inter-library dependencies. You need a build system (which would use gcc as the compiler) for that.
Now, the Nana library uses the CMake build system. Thus a good solution to the problem should be to get the authors of Nana to properly export the library's CMake targets, and distribute a .cmake file which you can then import if you also build with CMake.
Alternatively - perhaps such a CMake file already exists somewhere (I haven't been able to quickly find it though).
I would ask about this in the Nana forums.

Force CMake to use static libraries

[Shamelessly cross-posted from the CMake help list]
I'm trying to create binaries as statically as possible. The fortran code I've got has got X11 and quadmath as dependencies, and I've come across a number of issues (maybe each of these issues should be in a different question?):
My variables are currently
set(CMAKE_LIBRARY_PATH /usr/X11/lib /usr/X11/include/X11 ${CMAKE_LIBRARY_PATH})
find_package(X11 REQUIRED)
find_library(X11 NAMES X11.a PATHS /usr/X11/include/X11/ /usr/X11/lib)
find_library(X11_Xaw_LIB NAMES Xaw Xaw /usr/X11/include/X11/ /usr/X11/lib ${X11_LIB_SEARCH_PATH})
find_library(Xaw Xaw7 PATHS ${X11_LIB_SEARCH_PATH})
set(CMAKE_LIBRARY_PATH /usr/lib/gcc/x86_64-linux-gnu/4.7 /usr/lib/gcc/x86_64-linux-gnu/4.7/x32 /usr/lib/gcc/x86_64-linux-gnu/4.7/32 ${CMAKE_LIBRARY_PATH})
find_library(quadmath NAMES quadmath.a)
set(BUILD_SHARED_LIBS ON)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(LINK_SEARCH_START_STATIC TRUE)
set(LINK_SEARCH_END_STATIC TRUE)
set(SHARED_LIBS OFF)
set(STATIC_LIBS ON)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
Using these, CMake attempts to build every program statically (as expected) - however, it fails because I don't have Xaw.a - I can't find out whether this actually should exist. I have installed the latest libxaw7-dev which I was expecting to fix it. One option would be to compile the X11 libraries myself, but I don't really want to do that...
if I comment out only set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static"), then CMake compiles everything, but uses shared libraries for every program, even though I specify the location of .a X11 libraries in my find_library() calls. I was expecting CMake to use the .a files where it could and then only use shared libraries - is there a way to force this behaviour?
does anyone know yet of a fix for the bug described here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46539; whereby gfortran seemingly can't statically link libquadmath? I tried the fix using gcc but I can't get CMake to recognise the libgfortran flag:
cmake -DCMAKE_Fortran_COMPILER=gcc -DCMAKE_Fortran_FLAGS=-gfortran
results in
-- The Fortran compiler identification is unknown
-- Check for working Fortran compiler: /usr/bin/gcc
-- Check for working Fortran compiler: /usr/bin/gcc -- broken
CMake Error at /usr/share/cmake-2.8/Modules/CMakeTestFortranCompiler.cmake:54 (message):
The Fortran compiler "/usr/bin/gcc" is not able to compile a simple test program.
However, as you might have noticed, I set the location of the libquadmath.a; when I build a program which doesn't use X11 but does use quadmath when I use
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
then the program does compile successfully (running ldd reports 'not a dynamic executable') - does this mean that the bug has been fixed, or does it only work because I set the location in CMake?
I was having a similar problem. Turns out that cmake was implicitly linking against libgfortran and libquadmath. To fix this I put the following in my top level CMakeLists.txt:
unset(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES)
I could then explicitly link again the libraries using:
SET_TARGET_PROPERTIES(main_f PROPERTIES LINKER_LANGUAGE "C"
LINK_FLAGS
"/usr/local/Cellar/gcc/7.1.0/lib/gcc/7/libgfortran.a
/usr/local/Cellar/gcc/7.1.0/lib/gcc/7/libquadmath.a -lm -lgcc"
)
The static version of libgfortran is necessary because the shared library also depends on libquadmath. The added "-lm" and "-lgcc" bring in the system dynamic versions of these libraries. On a mac system, you would want to use the full path to your libm.a as well.
I guess your questions are not that much related, I don't know the answer for all of them.
For your static linking problems, since you're using GCC, you can pass multiple -static and -dynamic flags to it:
set(CMAKE_EXE_LINKER_FLAGS "-static ${STATIC_LIBS} -dynamic ${EVERYTHING ELSE} -static ${MORE_STATIC_LIBS}")
I don't know why Xaw.a isn't available on your system, probably because the package maintainer of your Linux distribution didn't really make them available.
Also, compiling everything static might make things not compatible between all distros out there and you cripple the ability for others to use improved, up-to-date libraries with your program, it might not be what you want.
If you intend to make a self-contained package of your program, it might be better just to include the shared libraries you used together, like Dropbox and many other proprietary applications do (Humble Bundle games are other example).

Linking a static boost build into a static library under VS2012 & Win32/64

I'm trying to build a static library to be released as an API for a network device. I can successfully compile and link the library to produce .lib output files, and I relocate them into a directory structure as follows:
EyeLib
L-Include
| L-PublicInterface.h
L-Lib
| L-debug
| | L-MyLib.lib
| | L-MyLib.pdb
| L-release
| L-MyLib.lib
L-MyLibConfig.cmake
Where the MyLibConfig.cmake file is extremely simple, and contains:
# the header file is relative to this cmake file, so get the path.
GET_FILENAME_COMPONENT( MyLib_TOPLEVEL_DIR ${CMAKE_CURRENT_LIST_FILE} PATH )
SET( MyLib_INCLUDE_DIR ${MyLib_TOPLEVEL_DIR}/include )
IF( WIN32 )
FIND_LIBRARY( MyLib_DEBUG_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib/debug )
FIND_LIBRARY( MyLib_RELEASE_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib/release )
SET( MyLib_LIBRARIES optimized ${MyLib_RELEASE_LIBRARY} debug ${MyLib_DEBUG_LIBRARY} )
ENDIF( WIN32 )
IF( UNIX )
FIND_LIBRARY( MyLib_LIBRARY MyLib ${MyLib_TOPLEVEL_DIR}/lib )
SET( MyLib_LIBRARIES "${MyLib_LIBRARY}" )
MARK_AS_ADVANCED( MyLib_LIBRARY )
ENDIF( UNIX )
# handle the QUIETLY and REQUIRED arguments
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyLib DEFAULT_MSG MyLib_LIBRARIES MyLib_INCLUDE_DIR)
MARK_AS_ADVANCED( MyLib_INCLUDE_DIR )
This build structure has worked for some test libraries I've built in the past, but I'm getting a link error when I try and use it to build a simple test app saying "error LNK1104: cannot open file 'libboost_thread-vc110-mt-s-1_54.lib'"
I can get the test app to build and run successfully if I add it to the same project as the library build. I assume this is because the library build is finding the boost libs to link against, so it propagates through to the executables in the project.
I built boost 1.54 with b2 link=static runtime-link=static threading=multi variant=debug,release --layout=tagged and linked both the library build and the test app build to the static MSVC runtime (/MT).
Can anyone offer some help/advice/further tests with this one? I need to make sure that all the boost stuff is compiled-in to the API library, so our clients don't have to install boost themselves.
Additional Info
In-case it's helpful, here's the cmakelists.txt file from the library build:
set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib")
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
find_package(Boost REQUIRED COMPONENTS system date_time regex thread chrono)
if(NOT WIN32)
list(APPEND Boost_LIBRARIES pthread)
endif()
include_directories(${Boost_INCLUDE_DIRS})
FILE(GLOB srcs *.cpp)
FILE(GLOB headers *.h)
set(libname MyLib)
set(deps ${Boost_LIBRARIES})
#To allow compilation. std=c++0x is for accepting the access to enums, which usually is just accepted with Visual Studio
IF( NOT WIN32 )
set (CMAKE_CXX_FLAGS "-fpermissive -std=c++0x")
ENDIF( NOT WIN32 )
SOURCE_GROUP( ${libname} FILES ${srcs} )
SOURCE_GROUP( "${libname}\\Hdr" FILES ${headers} )
add_library(${libname} ${srcs} ${headers})
target_link_libraries( ${libname} ${deps} )
This is by design.
When building a static library, any dependencies to that library will not get linked into the library directly. Instead when building an executable all library dependencies (direct and indirect) will be linked directly to that executable.
This is also the way most compiler handle static libraries. While VS does offer a special option to link dependencies into static libs, this is not possible on e.g. gcc without resorting to dirty file hacks. Since CMake only supports features that can be used on all supported generators, CMake will not allow to do this even on VS builds.
You have a couple of options now:
Use a dll instead of a static library (add_library(${libname} SHARED ...)). While a static library is basically a bunch of object files wrapped together, a dll is more or less the same as an executable. In particular, all static library dependencies get linked directly into the dll. The disadvantage here is that you have to deal with the usual dll mess: You have to specify which functions to export and the usual issues with passing stuff across dll boundaries apply.
Have your find script also search for all the dependencies. You should be able to restructure your library's dependency handling in a way that the amount of code duplication is minimal. The disadvantage is that configuring a third-party application becomes more difficult (especially on Windows) since you now not only need to find the library itself, but also all of its dependencies.
Use exported targets. This approach makes most sense if the library is built on the same machine as the final executable. Upon building the library, CMake auto-generates the config files for using that library. Your application then just needs to find an include that script and you're good to go. Disadvantage is that the export mechanism is not the most straight-forward feature of CMake, so you will have to spend some time to familiarize yourself with it.
Pull in the library sources directly into each executable. Basically each executable does an add_subdirectory on the library source dir. You still have to configure the dependencies for each executable and on top of that you also have to build the library seperately for each executable. You probably don't want to do this.

CMAKE: Build library and link against it

I'm trying to use cmake (on Linux with GNU make and g++) to build a project with two sub-directories: MyLib and MyApp. MyLib contains source for a static library; MyApp needs to link against that library. I'm trying to build on Linux with generated makefiles using the following CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (MyProj)
include_directories (MyLib)
file(GLOB MyLibSrc MyLib/*.cpp)
add_library(MyLibrary STATIC ${MyLibSrc})
file(GLOB MyAppSrc MyApp/*.cpp)
add_executable(MyApplication ${MyAppSrc})
target_link_libraries(MyApplication MyLibrary)
This 'almost' works. It fails at link time because while it generates libMyLibrary.a - it is in the root. When I add:
link_directories(${MyProj_BINARY_DIR})
it makes no difference.
I've got a few (inter-linked) questions:
What's the best way to coerce cmake into building my library and executable into a 'staging directory' — say MyStage — to keep targets separate from source?
How do I convince cmake to link the application against the library?
If I wanted to build a debug and a release version, what's the best way to extend my cmake scripts to do this — making sure that the debug application links against the debug library and the release application against the release library?
I'm a relative newcomer to cmake. I've read what I can find on the web, but find myself struggling to get my library to link with my executable. This sort of a configuration, to my mind, should be quite common. An example from which to crib would be very helpful, but I've not found one.
Well, it is better to read this example and do exactly as suggested.
cmake_minimum_required (VERSION 2.6)
project (MyProj CXX)
add_subdirectory(MyLib)
add_subdirectory(MyApp)
Then for each subdirectory specified, CMakeLists.txt files are created
MyLib\CMakeLists.txt
file(GLOB SRC_FILES *.cpp)
add_library(MyLib ${SRC_FILES})
MyApp\CMakeLists.txt
file(GLOB SRC_FILES *.cpp)
add_executable(MyApp ${SRC_FILES})
target_link_libraries(MyApp MyLib)
Use "out of the source build". Make a directory used only for build and while in it, call
cmake <path to the sources, it may be relative>
Either use
link_directories(${MyProj_BINARY_DIR}/MyLib)
or make CMakeLists.txt in each subdirectory - that would be better for project larger than very small.
This is a bit tricky, check out CMAKE_BUILD_TYPE in the docs (you can set it and/or "if" by it). You can also set it from command line:
cmake -DCMAKE_BUILD_TYPE=Debug
I've discovered the 'optimal' solution to (1)... so, thought I should post it here:
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY MyStage)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY MyStage)
The thing that confused me previously is that static libraries are not considered a LIBRARY by Cmake - they're considered to be ARCHIVEs.
Do not add libraries and executables in the root Cmakelists.txt. Add these libraries and executables in Cmakelists.txt of subdirectories.

Resources