How to statically link Qt libraries? - c++

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!

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.

Cmake links multiple versions of boost/Cmake separate compilation of source files

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.

Using /usr/lib/i386-linux-gnu instead of /usr/lib/x86_64-linux-gnu to find_library in CMake

How can I make CMake look for i386 libraries instead of x86_64 ones?
I'm trying to build i386 linux executables on machine for later deployment. I've made sure I've installed the i386 version of my dependencies, and they under /usr/lib/i386-linux-gnu, while the 64bit libraries are under /usr/lib/x86_64-linux-gnu, as expected.
However, I can't seem to find a way to make CMake look under /usr/lib/i386-linux-gnu for my libraries when building 32 bit. Setting make CMAKE_CXX_FLAGS to include -m32 only causes linking to fail, since the compiler is building a 32 bit executable and trying to link 64bit libraries to it, which it obviously can't do. It does this because it somehow prefers to get /usr/lib/x86_64-linux-gnu/libsfml-system.so over /usr/lib/i386-linux-gnu/libsfml-system.so for example.
What I've tried so far:
Adding -m32 to my compile flags, caused executable not to link
Setting my CMAKE_FIND_ROOT_PATH to /usr/lib/i386-linux-gnu, hoping it would look under that directory first, though it still found the 64 bit versions of the libraries.
I don't really have any more ideas, although I'm actively researching on forums, but I can't seem to find much that is useful. Maybe someone here has an idea of what I could do next.
My CMakeLists.txt as of now:
cmake_minimum_required(VERSION 3.5)
project(Synapse)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread -O3 -m32")
set(CMAKE_SYSTEM_PROCESSOR i386)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION gnu)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake_modules)
find_package(SFML 2.4 COMPONENTS system window graphics network audio REQUIRED)
include_directories(${SFML_INCLUDE_DIR})
message(STATUS ${SFML_LIBRARIES})
set(CLIENT_SOURCE_FILES Client/main.cpp types.h Client/Mouse.cpp Client/Mouse.h Client/Game.cpp Client/Game.h Client/Camera.cpp Client/Camera.h Client/Renderer.cpp Client/Renderer.h Networking.h)
add_executable(SynapseClient ${CLIENT_SOURCE_FILES})
set(SERVER_SOURCE_FILES Server/main.cpp types.h Server/Game.cpp Server/Game.h Server/Commander.cpp Server/Commander.h Server/Unit.cpp Server/Unit.h Server/Client.cpp Server/Client.h Networking.h Server/Log.cpp Server/Log.h Server/User.cpp Server/User.h)
add_executable(SynapseServer ${SERVER_SOURCE_FILES})
target_link_libraries(SynapseClient ${SFML_LIBRARIES})
target_link_libraries(SynapseServer ${SFML_LIBRARIES})
Let CMake know that you do not want to search the 64bit paths before calling
find_package():
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS OFF)
Documentation:
FIND_LIBRARY_USE_LIB64_PATHS
FIND_LIBRARY_USE_LIB32_PATHS

CMake cannot find boost libraries in my host computer for cross compiler but was found in Raspberry Pi

I downloaded libboost1.50-all in Raspberry Pi and has successfully compiled and execute a program using threads. Libraries were also found in CMake. I then copied the libraries of the boost and its include from /usr/lib and /usr/include/boost respectively to C:\Boost such that the hierarchy becomes:
C:
-> Boost
-> lib
... files
-> include
-> boost
... files
I then used the same CMakeLists.txt and the source code but the library was not found.
NOTE: The cross compiler that I used is fully working and I was able to produce an executable with CMake in Cygwin using the std library. I even specified the location of the library and the user and the root.
Is there anything that I missed out?
cmake_minimum_required(VERSION 2.8)
set(BOOST_ROOT C:/Boost/)
set(BOOST_INCLUDEDIR C:/Boost/include/)
set(BOOST_LIBRARYDIR C:/Boost/lib/)
SET(Boost_DEBUG ON)
find_package(Boost 1.50.0 COMPONENTS thread system)
if (Boost_FOUND)
include_directories (${Boost_INCLUDE_DIRS})
add_executable (thread thread.cpp)
target_link_libraries(thread ${Boost_LIBRARIES})
endif()
Use CMAKE -GUI and then check whether your boost libraries are detected . If not then manually set in the CMAKE-GUI and configure again.
TEMPORARY SOLUTION that I was able to come up to!
I placed the boost lib and include to where the cross compiler is installed since the cross compile was able to link the source code to libstdc++.
The library is placed here:
C:\cygwin\opt\cross\x-tools\arm-unknown-linux-gnueabi\arm-unknown-linux-gnueabi\sysroot\lib
The include files are placed here:
C:\cygwin\opt\cross\x-tools\arm-unknown-linux-gnueabi\arm-unknown-linux-gnueabi\include\c++\4.6.3
The CMakeLists content is as follows now:
cmake_minimum_required(VERSION 2.8)
add_executable (thread main.cpp)
target_link_libraries(thread boost_thread boost_system)
Open Cygwin terminal and invoke cmake there, then make. Viola! It now compiles successfully! :>
The magic lies in here:
target_link_libraries(thread boost_thread boost_system)
I found this in one of the questions here in Stackoverflow where someone said to manually link the libraries..
Even though that it worked, why is it that CMake cannot detect the boost library both in Windows (Cygwin terminal) and Linux (VMware) -- These I tried -- but the library was found in Raspberry Pi (Raspbian) using the same CMakeLists.txt and main.cpp. Isn't it the purpose of CMake is to find the libraries itself? If I were just to link them manually, better do it like this then:
arm-unknown-linux-gnueabi-g++.exe -lboost_thread -lboost_system

Using CMake to statically link to a library outside of the project

I would like to use CMake to link my project to my shared library. The library is only shared between a handful of projects and is rather small, so I would really like to build it before it is linked. Building it every time seems a better idea than having to maintain an up-to-date precompiled version, because I ten to change it together with the project. It is separate, because it contains stuff I will almost certainly need in the next project.
How can I configure CMake to do it?
My current CMakeLists.txt for the relevant project looks like this:
find_package( Boost REQUIRED COMPONENTS unit_test_framework)
include_directories(${BaumWelch_SOURCE_DIR}/../../grzesLib/src
${BaumWelch_SOURCE_DIR}/src
${Boost_INCLUDE_DIRS})
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-g -std=c++11 -Wall -Werror -Wextra -pedantic -Wuninitialized)
endif()
# Create the unit tests executable
add_executable(
baumwelchtests stateindextest.cpp baumiterationtest.cpp baumwelchtest.cpp sampleparameters.cpp sdetest.cpp
# Key includes for setting up Boost.Test
testrunner.cpp
# Just for handy reference
exampletests.cpp
)
# Link the libraries
target_link_libraries( baumwelchtests ${Boost_LIBRARIES} baumwelchlib grzeslib)
but obviously the compilation fails with:
/usr/bin/ld: cannot find -lgrzeslib
You mentioned you'd like to build the library rather than use a precompiled version. If the library has a CMakeList, you should add it using add_subdirectory(path/to/the/library/source/directory). It will then become a subproject of your project and you can use names of its targets normally in your CMakeList.
Note that while the command is called add_subdirectory, it can be an arbitrary directory on disk; it doesn't have to be a subdirectory of the master project's source dir. In case it's not a subdirectory, you have to explicitly specify a binary directory for it as well. Example:
add_subdirectory(/path/to/the/library/source/directory subproject/grzeslib)
The second argument, if given as a relative path, is interpreted relative to CMAKE_CURRENT_BINARY_DIR.