Add compile option if shared lib is linked - gcc

I have a special compiler that need an extra flag -non-static when linking an executable to with an shared lib:
gcc main.cpp -non-static -lshared -o main
(Note: Its the compiler for vxworks)
How can i do this in CMake?
Solutions i have used so far (but are not satisfying):
Always set -non-static in the toolchain file. Works, but has unwanted side effects when you dont need any shared lib.
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-non-static")
Create a INTERFACE library with -non-static compile option set. However, each new project must rewrite this and and each executable must link this library (if it links any shared lib):
add_library(allwaysLinkMe INTERFACE)
if(CMAKE_SYSTEM_NAME STREQUALS "VxWorks")
target_link_libraries(allwaysLinkMe INTERFACE "-non-static")
endif()
add_library(shared SHARED a.cpp)
add_executatble(main main.cpp)
target_link_libraries(main shared allwaysLinkMe)
Or i link this library to all other shared libraries:
add_library(shared SHARED a.cpp)
target_link_libraries(shared allwaysLinkMe)
add_executatble(main main.cpp)
target_link_libraries(main shared)
In both cases, I must use ifs to prevent this from failing with other target platforms. Also both are pretty ugly and error prone.
I am looking for a solution, that is only in the toolchain/platform/compiler file(s) and no change to the project must be made.

Related

cmake: using shared library while building when only headers exist

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.

Library's CMake generates DLL. Application's CMake wants LIB

My library has minimal, straightforward CMake code with the pertinent lines
add_library(MyLib <sources>)
install(
TARGETS MyLib
LIBRARY DESTINATION ${destination}/lib
RUNTIME DESTINATION ${destination}/lib
COMPONENT Libraries)
install(
FILES mylib.h
DESTINATION ${destination}/include
COMPONENT Headers)
When executed under Windows, the system generates mylib.dll in ...\build\Release, and mylib.lib and mylib.exp (what's that?) in ...\build\lib\Release. It only installs mylib.dll.
My application has minimal, straightforward CMake code to search for my library:
find_path(MyLib_INCLUDE_DIR mylib.h)
find_library(MyLib_LIBRARIES NAMES MyLib)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib DEFAULT_MSG MyLib_LIBRARIES MyLib_INCLUDE_DIR)
Which works under Linux, but under Windows results in
-- Could NOT find MyLib (missing: MyLib_LIBRARIES)
From experimentation I know that this error occurs whenever there is only a .DLL file, and no associated .LIB import library.
Shall I correct MyLib to install mylib.lib? How?
Or is it possible to modify my application so that it is satisfied with mylib.dll only? How?
Research done so far
This is not about static vs dynamic linking (DLL and LIB files - what and why?, cmake link against dll/lib): I want dynamic linking; if a .LIB file is required, it has nothing to do with static linking.
This link cmake : shared library : how to get the .lib name instead of .dll name? may be pertinent, but is not explicit enough. Two other questions CMake generated VS project expecting lib instead of dll, Linking dll/lib to a cmake project seem related, but have no answer.
Command install classifies .lib file for a shared library as ARCHIVE. This is explicitly stated in the documentation:
For DLL platforms (all Windows-based systems including Cygwin), the DLL import library is treated as an ARCHIVE target.
So you need to add ARCHIVE clause to install() for install .lib file as well:
install(
TARGETS MyLib
ARCHIVE DESTINATION ${destination}/lib
LIBRARY DESTINATION ${destination}/lib
RUNTIME DESTINATION ${destination}/bin
COMPONENT Libraries)
Not also, that RUNTIME DESTINATION is usually specified as bin, the same as destination for executables. This helps the executables on Windows to locate the shared libraries (.dll).

Why is the CMake solution for "R_X86_64_32 can not be used when making a shared object" specific to x86_64?

I just got this error when compiling some plugins for my new toy (on gcc/g++ on Linux):
relocation R_X86_64_32 can not be used when making a shared object; recompile with -fPIC
I basically understand why PIC is needed but, within the CMake system, the solution seems to be this:
IF (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
SET_TARGET_PROPERTIES (${PLUGIN_BASE_LIB} PROPERTIES COMPILE_FLAGS "-fPIC")
ENDIF (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
I don't understand why this solution is conditional.
The follow-up seems to suggest that -fPIC should be used basically everywhere except 32-bit Linux, which suggests that the above is not portable.
Should I always use -fPIC? Will there be any adverse effects?
${PLUGIN_BASE_LIB} needs to be statically linked to both the main executable, and statically the various shared libraries which are the plugins.
Ideally you want to build two versions of code: one for the main executable and one for the library. The first will need to be compiled with -fPIE (which is default in modern distros) and the second with -fPIC. As you point out this does not depend on target architecture.
You can compile only one version with -fPIC but then main executable will be suboptimal because -fPIC forces compiler to obey symbol interposition rules which significantly limits it's ability to optimize code e.g. inline and clone functions.

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.

Resources