Cmake links multiple versions of boost/Cmake separate compilation of source files - c++

I'm trying to build my project on a cluster, so I don't have any influence on the environment (ie no sudo). On my local machine I can get it to work.
Here the problem:
My project contains cuda files as well as c++ code. The latter one requires a library that needs gcc/g++ >6 (maybe >5 would work as well, afaik std=c++14). The cuda code on the other hand, as of cuda 7.5 needs gcc < 5.
I've already got this issue done by using the g++ 6.2.0 as standard compiler and pass the other gcc with -ccbin /path/to/gcc-4.x.
So my code compiles fine, but the problem is that it also uses the boost library, which needs to be a newer version on the cluster to work with the gcc 6.2.0 than the one I locally use. This is also not the problem itself, as linking the correct one does work, BUT when doing so, the nvcc still links an older version of boost (that is compatible with the gcc-4.x) and thus resulting in having multiple boost library version linked. This leads to segmentation faults during run time, whenever a function of the old boost library is used.
So a solution I was thinking about would be first compiling the c++ files and then only the cuda files, kinda like a simple makefile target would do:
foo: foo-class.o
nvcc foo-class.o foo.cu -o foo
I'm currently unsure if this would solve the problem and if this is possible to do with cmake, but if that is not the case, is there a possibility to take care of the double linkage?
Minimal cmake file example of how mine currently looks:
cmake_minimum_required(VERSION 3.2)
project(foo)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(LINKER_FLAGS "-lboost_program_options -lboost_regex -lSDL2 -lSDL2main -lboost_system -lboost_filesystem")
set(ADDITIONAL_FLAGS "-g -Wno-error=switch")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ${LINKER_FLAGS} ${ADDITIONAL_FLAGS}")
set(SOURCE_FILES
runtime/main.cpp
foo.cpp)
set(CUDA_FILES cuda/food.cu)
set(CUDA_ADDITIONAL_FLAGS "-ccbin /usr/bin/gcc --Wno-deprecated-gpu-targets")
set(CUDA_SDK_ROOT_DIR "/afs/crc.nd.edu/x86_64_linux/c/cuda/8.0/")
find_package(CUDA QUIET REQUIRED)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
set(CUDA_NVCC_FLAGS -g ${CUDA_ADDITIONAL_FLAGS})
FIND_PACKAGE(Boost COMPONENTS program_options filesystem system regex REQUIRED)
cuda_add_executable(isosurfaces ${SOURCE_FILES} ${CUDA_FILES})
include_directories(~/lib/include)
include_directories(${BOOST_ROOT}/incldue)
target_link_libraries(foo ~/lib/lib/libThorSerialize17.so)
Thanks for any help, I really appreciate it.

To improve the CMake file I would suggest to use the variables provided by the Boost find script instead of manual setting (that will however most likely not help with the issue itself, but good in general):
find_package(Threads)
# set(Boost_USE_STATIC_LIBS ON) # uncomment to try with static libs
FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options filesystem system regex)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
target_link_libraries(isosurfaces
${Boost_LIBRARIES}
${CUDA_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
# remove -lboost_program_options -lboost_regex -lboost_system -lboost_filesystem
# from LINKER_FLAGS as provided better by ${Boost_LIBRARIES}
Regarding the issue itself with the different versions of Boost (if you really need to use Boost in the Cuda code for some reason), I'm afraid that will be quite difficult to get working in scope of a single executable. What you can do however, is to separate one of the modules (either the Cuda or the application code) to a separate shared library. That way it could work relatively straightforward, as the shared library can use a different Boost version than the rest of the application (you can experiment with using either static or shared Boost libraries, i.e. Boost_USE_STATIC_LIBS switched ON/OFF).
For example to create a shared library from the Cuda code you could do:
cuda_add_library(isosurfaces_cuda ${CUDA_FILES} SHARED)
add_executable(isosurfaces ${SOURCE_FILES})
target_link_libraries(isosurfaces
isosurfaces_cuda
${Boost_LIBRARIES}
${CUDA_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
Then it could probably work, provided that you do not use Boost in the interface between the Cuda code and the remaining C++ code.
It can also help to use the visibility attribute and hide all symbols by default, so that the Boost library symbols will not be exported from the Cuda shared library (or the other way around, if the library is created from the remaining C++ code). For that the "-fvisibility=hidden" compiler flag and "-Wl,--exclude-libs=ALL -Wl,--discard-all" linker flags can be used.

Related

How do I link to a static library (libtiff) using CMake in my wxWidgets project?

For my wxWidgets project, I am trying to make the switch from my self-written Makefile to Cmake. I develop on macOS.
When I was writing that Makefile I ran into an issue with libtiff. I wanted to statically link my application so that I don't have to distribute any dylibs myself or rely on my users to install them. I built wxWidgets as a static library but when I compiled my code and checked my binary with otool I always found that my binary required a local dylib.
/usr/local/opt/libtiff/lib/libtiff.5.dylib
Finally I found a solution on here. In essence, in the linking line of my Makefile I replaced wx-config –-libs with LDFLAGS. LDFLAGS looks like this:
WXCONFIGLIBS := $(shell wx-config --libs)
WXCONFIGLIBS := $(WXCONFIGLIBS:-ltiff=/usr/local/opt/libtiff//lib/libtiff.a)
# I am not sure whether the double slash is a typo but it works so I don't change it
LDFLAGS := $(WXCONFIGLIBS)
Basically, I search-and-replaced -ltiff with the path to my static libtiff library.
Now I've managed to compile my project using Cmake. However, I'm getting the same warning message as I did when I battled my original issue.
ld: warning: dylib (/usr/local/lib/libtiff.dylib) was built for newer macOS version (11.0) than being linked (10.11)
How do I fix this? My CMakeLists contains these sections pertaining to wxWidgets:
find_package(wxWidgets REQUIRED gl core base OPTIONAL_COMPONENTS net)
include(${wxWidgets_USE_FILE})
...
add_executable(myapp ${SOURCES})
target_link_libraries(myapp ${wxWidgets_LIBRARIES})
set_property(TARGET myapp PROPERTY CXX_STANDARD 17)
I already tried running some search-and-replace shenanigans like
string(REPLACE "-ltiff" "/usr/local/opt/libtiff/lib/libtiff.a" wxWidgets_LIBRARIES ${wxWidgets_LIBRARIES})
But that doesn't work. It does replace -ltiff but also seems to remove the semicolons and whitespaces separating the different libraries.
I've been scouring the web for any clues as to what to do, but I don't seem to have a good enough grasp of libraries to fix this.
Any help would be greatly appreciated.
Set wxWidgets_USE_STATIC=ON before calling find_package(wxWidgets). See the documentation for wxWidgets here: https://cmake.org/cmake/help/latest/module/FindwxWidgets.html
option(wxWidgets_USE_STATIC "Link to wxWidgets statically" ON)
find_package(wxWidgets REQUIRED gl core base OPTIONAL_COMPONENTS net)
include(${wxWidgets_USE_FILE})
...
add_executable(myapp ${SOURCES})
target_link_libraries(myapp PRIVATE ${wxWidgets_LIBRARIES})
target_compile_features(myapp PRIVATE cxx_std_17)
My search-and-replace idea turned out to be not so bad. I was able to achieve the same outcome with Cmake as with my Makefile.
My problem was not using double quotes in the appropriate place. So instead of this:
string(REPLACE "-ltiff" "/usr/local/opt/libtiff/lib/libtiff.a" wxWidgets_LIBRARIES ${wxWidgets_LIBRARIES})
I simply needed to write:
string(REPLACE "-ltiff" "/usr/local/opt/libtiff/lib/libtiff.a" wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}")
So to solve my actual problem, I am calling this string() command just before the target_link_libraries() command.

Static link boost library with shared library in CMakeLists.txt

I am trying to build an executable, and to change the link for boost library to static. The codes that I am trying to compile is here.
I am using Xubuntu 14.04, cmake 3.5.1, boost 1.54.
The error I got is:
Linking CXX shared library ../../lib/librexd.so
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_system.a(error_code.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_system.a: error adding symbols: Bad value
Things I have done:
Set boost library to static link in CMakeLists.txt (an example):
set(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE(Boost 1.46.0 COMPONENTS system regex program_options thread filesystem REQUIRED)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(rexd ${Boost_LIBRARIES})
There are alot of CMakeLists.txt, so I did the above for 3 of them that uses Boost.
Next, I set the compiler flag to -fPIC for CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_DEBUG, for example:
SET (CMAKE_CXX_FLAGS "-D_REENTRANT -fpic")
SET (CMAKE_CXX_FLAGS_DEBUG "-g -Wall -fpic")
Again, I did it for all CMakeLists that have CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_DEBUG variables.
Lastly, I recompile boost with -fPIC option. I downloaded boost.tar.gz from sourceforge, extract it, and ran this:
bjam clean
bjam -d+2 link=static cxxflags="-fPIC" install
However, this does not seem to change anything. the date modification for libboost_system.a is dated a few years ago.
I have tried to tinker with add_library, making this static
ADD_LIBRARY(rexd STATIC ${sources_symbolic} ${sources_parsers} ${sources_lfit} ${sources_teacher} ${sources_rexd} ${sources_ippc_planner})
I got this error instead where it couldn't find a header .h:
No such file or directory
How should I proceed? I apologize if this question is too specific for my use case, but I can't find any other answers out there that I haven't tried.

How to statically link Qt libraries?

I want to statically link Qt libraries to my program so that It can run in my school computer.We don't have purmision to install anything on those computer thus statically linking is my only chance .
So far this is my cmake file
cmake_minimum_required(VERSION 3.9)
project(Calculator)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpedantic -Wextra -std=gnu++14 -no-pie -fPIC -static -lQt5Widgets -lQt5Gui -lQt5Core")
find_package(Qt5Widgets REQUIRED)
include_directories(/usr/include/qt/QtWidgets /usr/include/qt /usr/include/qt/QtGui /usr/include/qt /usr/include/qt/QtCore /usr/include/qt)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
add_executable(${PROJECT_NAME} main.cpp calculator.cpp resources.qrc calculatestring.cpp )
here is what I get when I try to run this cmake file:-
/bin/ld: cannot find -lQt5Widgets
/bin/ld: cannot find -lQt5Gui
/bin/ld: cannot find -lQt5Core
if I remove -static flag ,it compiles fine but only runs on machine on which qt is installed.
when I try to run it on my VirtualMachine with Arch Linux which doesn't have qt installed it give me error:-
error while loading shared libraries : libQt5Widgets.so.5: cannot open shared file: No such file or directory
I want(have no other choice) to run my program run without installing Qt on those machines .
Edit:-
Question likened as Possible Duplicate shows how to link with Qmake. I am using cmake .Also my question is not limited to the Qt.
I assume from your answer you are developing on Linux.
The problem you are facing does not depend on the building system (cmake, qmake, or else).
To link your program to a static version of a library you need that library on your development machine. In your case, you have the dynamic version of the library (the .so file), but you don't have the static one (the .a). Hence, when you try to link statically, the linker (ld) says it can't find the file.
For licensing issues, Qt open source binaries are distributed only as dynamic libraries. If you need to link Qt statically, you have to build it yourself.
I invite you to read the official documentation here if you are interested in attempting this.
However, you may not need to link statically, if your problem is just to get the executable on the target machine without installing extra packages.
You can deploy your application copying the executable and the .so files needed to the target machine, the same way you would copy an .exe file together with all the .dll files needed, if you were running on Windows.
You can use the command ldd to obtain the list of dynamic libraries your executable needs.
However, Linux works in a different way and one can not simply copy over the .so files. You must provide the loader the path where to look for .so files. This can be done setting the LD_LIBRARY_PATH enviromental variable. You will find plenty of examples on the internet on how to set this variable correctly.
Alternatively, you may also consider to build a snap package, if this is allowed on your target machine.
Good luck with your school project!

Linking GSL in CMakeLists.txt

I have a code with multiple files, that uses the GSL Library. When I compile the code through the terminal with the command
g++ main.cpp -lm -lgsl -lgslcblas -o Exec
This compiles and gives the correct output and no errors.
However, when I try and build the code in CLion I get the error
undefined reference to `gsl_rng_uniform'
I have linked the various .cpp files in my code through the CMakeLists.txt, but I think, I have to something similar to the flags to link to GSL.
My CMakeLists.txt file is as follows currently (only the .cpp files are included in the source files, not the .h files):
cmake_minimum_required(VERSION 3.7)
project(Unitsv1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp
transition.cpp
random.cpp)
add_executable(Unitsv1 ${SOURCE_FILES})
I'm very new to C++, and can't seem to find any answers online.
Thanks
You haven't linked in the GSL libraries, so the linker won't find any of the symbols it provides. Something like this should get you most of the way there:
cmake_minimum_required(VERSION 3.7)
project(Unitsv1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES) # See below (1)
set(SOURCE_FILES main.cpp
transition.cpp
random.cpp)
add_executable(Unitsv1 ${SOURCE_FILES})
find_package(GSL REQUIRED) # See below (2)
target_link_libraries(Unitsv1 GSL::gsl GSL::gslcblas)
If your code uses C++11, then you need the line at (1) to ensure you actually get C++11 support. Without CMAKE_CXX_STANDARD_REQUIRED YES, the CMAKE_CXX_STANDARD variable acts only as "Use it if it is available, or fall back to the closest standard the compiler can provide". You can find a detailed write-up here if you're curious.
The more important part for your question is at (2). The find_package() command looks for the GSL libraries, etc. and makes them available as import targets GSL::gsl and GSL::gslcblas. You then use target_link_libraries() to link your executable to them as shown. The CMake documentation explains how the find_package() side of things works in plenty of detail:
Start here: find_package()
Specifics for GSL: FindGSL module
Linking: target_link_libraries()

how to include NTL using CMake

I use this line to compile a simple program:
g++ main.cc -lntl -lm -lgmp
How do you include this into CMake?
find_package(NTL REQUIRED)
find_package(GMP REQUIRED)
Doesn't work. And gives the following error:
CMake Error at CMakeLists.txt:30 (find_package):
Could not find module FindNTL.cmake or a configuration file for package
NTL.
...
.
and
SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++0x -lntl -lm -lgmp)
Doesn't work either (but I think it's just wrong in general).
Thank you!
If ntl, m, and gmp libraries are usually installed to somewhere in the default path (e.g. /usr/ or /usr/local/), you could simply do something like:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_executable(test main.cc)
target_link_libraries(test ntl m gmp)
This is probably closest to your original g++ command, but it isn't very robust however; if any of the libraries aren't found, you won't know about it until you try linking. If you want to fail at configure time (i.e. while running CMake), you could add find_library calls for each of the required libs, e.g.
find_library(NTL_LIB ntl)
if(NOT NTL_LIB)
message(FATAL_ERROR "ntl library not found. Rerun cmake with -DCMAKE_PREFIX_PATH=\"<path to lib1>;<path to lib2>\"")
endif()
You'd then have to change your target_link_libraries command to
target_link_libraries(test ${NTL_LIB} ${M_LIB} ${GMP_LIB})
You'd probably also then have to do a find_file for one of each lib's header files to find out the appropriate path to add via the include_directories command (which translates to -I for g++).
Note, it's important to put quotes around the extra CXX_FLAGS arguments, or CMake treats them like separate values in a list and inserts a semi-colon between the flags.
For further information about find_library, find_file, etc. run:
cmake --help-command find_library
cmake --help-command find_file
Regarding your error:
It doesn't look like there's a FindNTL.cmake module included with CMake. That means you'll have to either:
Write your own FindNTL.cmake,
Find another that somebody else has written,
Hack together a solution that:
Checks if NTL is installed
Provides link targets, relevant flags, etc.
From a (rather quick) Google search, it appears somebody has an NTL module for CMake. Since NTL use GMP, you will probably need the associated GMP module for CMake. It doesn't look like a fully-featured CMake module, but it also appears to be the best thing out there (again, it was a quick Google search, and I don't use NTL).
To use, you'll want to add some things to your CMakeLists.txt:
# Let CMake know where you've put the FindNTL.cmake module.
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/CMake/Modules")
# Call the FindNTL module:
find_package(NTL REQUIRED)
SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=c++0x -lntl -lm -lgmp)
Yes, this is wrong. You don't want to be setting your CXX_FLAGS with linking directives. I would use:
SET ( CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=cxx0x )
to set the Cxx standard you want to use. To actually link to libraries, you'll want to:
Ensure that you've found the libraries (with the relevant find_package ( FOO ) lines)
Link those against your target, like this:
# Build the Foo executable. (Or library, or whatever)
add_executable (FooEXE ${Foo_SOURCES} )
target_link_libraries (FooEXE
${bar_LIBRARIES}
${baz_LIBRARY}
)
Please note! ${bar_LIBRARIES} and ${baz_LIBRARY} is not a typo; there's no standard way of setting the relevant libraries in the FindFOO.cmake modules, which is, in my opinion, an annoyance. If one doesn't work, try the other, or, worst case, have a look in the relevant FindFOO.cmake file (there's a bunch installed with CMake by default) to see what each one uses. With the link i provided, you can use ${NTL_LIB} and ${GMP_LIB}.