I have been trying to compile TinyXML using CMake as a sort of mini project, trying to learn CMake. As an addition I am trying to make it compile into a dynamic library and install itself so it works.
So far I have managed to get it to compile and install BUT it compiles into a .dll and a .dll.a and the only way to get it to work is to have it install into both /bin and /lib, which makes it install both files in both folders. This setup works but I'm guessing the .dll should be in /bin and the .dll.a should be in /lib. Is this some sort of Cygwin-specific problem or am I doing something wrong?
The .dll is the runtime library file, which must be present on the target system on run time (and be in $PATH there). The .dll.a file is the import library for the .dll, which must be present on the compiling machine at link time. You need to distribute the .dll file to the places where the program should run, and both .dll and .dll.a to places where the library is used to link other programs. you don't need the .dll.a file on the machines running the program only.
When you don't want to create a shared library, you can tell this to cmake with the static keyword in the add_library command:
add_library(mylib STATIC foo.c bar.cpp)
This way there will no shared library created, but the code from the library will be added by the linker into the final executable file.
What you need is to specify a destination for each type of file.
The .dll is considered a RUNTIME library and the .a is an ARCHIVE. Just in case, for other platforms, you probably want the LIBRARY entry (for .so files).
install( TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
)
Related
During the setup of my project - when I knew even less than I do now about cmake - I was trying my hardest to link the FFTW library.
C:\\path\\to\\fftw-3.3.5-dll64 contains the .h files, .lib files (generated from .def files) and .dll files.
What I ended up doing was adding these links to my CMakeLists.txt:
add_executable(${TargetName} PRIVATE main.cpp)
target_include_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_libraries(${TargetName} PRIVATE libfftwf3-3)
After building this, the application was still not working. Eventually, I figured out that on opening the executable, windows was looking for the libfftw3-3 dll file. At the time I just wanted to get it working, so I copied the .dll files that are included with the library - even though this is shared/dynamic linking, not static linking.
I'm now trying to properly statically link the library; I removed the dll's from my build folder and filtered my CMakeLists.txt file down to:
add_executable(${TargetName} PRIVATE main.cpp)
target_include_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_libraries(${TargetName} PRIVATE libfftwf3-3)
This builds, as I would expect it would. However, even though, in my CMakeLists.txt file, I've taken the steps to statically link the library, I'm still required to copy the dll's over in order for the executable to run (its dynamically linking still).
(Successful) verbose build output: https://pastebin.com/bbrZdd7r
The LIB files you generated from the DEF files are "stubs". They contain just enough code to load the DLL and call functions from it. They do not contain the actual FFTW code. You cannot statically link with these pre-built FFTW LIBs.
You will need to compile FFTW into a static library yourself first. It comes with a CMake build file where you can turn off BUILD_SHARED_LIBS.
edit: on review, your question is nearly identical to this one, with the same answer.
libs can be either static or dynamic. The one's generated (following the instructions in the README-WINDOWS file) are shared (they link to the .dll files inside the same folder.
With the windows binaries provided by FFTW, you cannot statically link (because all they provide are the dynamic libraries (.dlls). If you look at the file size of the .lib file, it's very small, because it's just a reference to the .dlls.
Follow the instructions on FFTW's windows page, for building the library from the source. Because you're now building the library yourself, you have the option to turn of "shared-library" and make a "static" lib.
I have a question related to how to install a built executable program with cmake when it relies on some external libraries. Suppose my executable is abc, and it relies on two external libraries: lib1.so and lib2.so. The structure of the codes are as follows:
-.........
|----bin (lib1.so lib2.so)
|----include(lib1.h lib2.h)
|----src(main.cpp)
When the executable program is installed using the following cmake commands:
INSTALL(TARGETS ${Exe_Name}
RUNTIME DESTINATION Path to bin
LIBRARY DESTINATION Path to bin)
I expect that the executable program will be in the same directory with lib1.so and lib2.so. However, when I execute the built program in the installation folder, I met the following error:
error while loading shared libraries: lib1 can not open shared object file No such file or directory
If I use ldd to check the executable, I found lib1.so and lib2.so not found. After searching for possible solutions, I found if I call the executable in this way, then it worked:
LD_LIBRARY_PATH=./ ./my_program_run
Then my question is how I can let my executable program knows the locations of the shared libraries with cmake when it is installed? Thanks.
This is best solved this with the RPATH of the final executable. RPATH is a hardcoded search path for the executable itself, and allows the use of the string $ORIGIN, which expands to the location of the executable at runtime. See this reference: http://man7.org/linux/man-pages/man8/ld.so.8.html
CMake strips the rpath of a binary at installation time, to avoid the binary picking up libraries littered around your development tree. But it also provides a simple way to modify the installation rpath for exactly this reason. Here's the short answer:
IF(UNIX)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
This particular example appends to the existing rpath, and adds . and ../bin to the search path, all relative to the location of the binary.
Some developers claim that adjusting the RPATH of the binary is not a good idea. In the ideal world, all the libraries would live in the system library directories. But if you take this to the extreme, you end up with Windows (at least the older ones), where c:\windows\system32 is full of junk that came from who knows where, and may or may not conflict with other software, etc. Using rpath and installing everything in one place seems like a great solution.
If the application is to be cleanly installed to a standard linux distribution, then you should either install the supporting shared libraries into a standard location (/usr/lib), or you should add the libraries location to the ld.so config, by create an /etc/ld.so.conf.d/myprogram.conf file containing the name of the directory the libraries are in.
If the installation is temporary or more ad-hoc, then a script to set the LD_LIBRARY_PATH is suitable.
The libraries are searched in the predefined locations which includes standard library paths configured with ld.so.conf and LD_LIBRARY_PATH. You can also try to compile your app with -rpath, but it is not recommended by some developers. I suggest you to create a wrapper script which will set LD_LIBRARY_PATH and run the real application like that:
"theapp" script:
#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application
The application, script and libraries should be in the same location (under bin/).
I have some CMake packages that depend on Protobuf v2.5, and one that depend on Protobuf v3.4. I have v2.5 installed system-wide in /usr, whereas v3.4 is only used in a single package. Therefore, I put the headers for v3.4 in a 3rdparty subdirectory inside the package where it is being used, and then I call include_directories(3rdparty) in my CMakeLists.txt so it can be found.
As for the shared libraries, the .so files for v2.5 are present in /usr/lib/x86_64-linux-gnu, and I installed the .so files for v3.4 to /usr/lib. In short, this is what the directory structure looks like:
v2.5:
headers: /usr/include
libraries: /usr/lib/x86_64-linux-gnu
v3.4:
headers: <MY_PACKAGE_SRC_DIRECTORY>/3rdparty
libraries: /usr/lib
Now, the problem arises when I try to link against v3.4. To simplify things, I don't use any CMake module files to find protobuf v3.4, rather I just add a hard-coded path /usr/lib/libprotobuf.so to the list of libraries to link against when creating a target. But even so, when I run ldd my_target_executable, the result is:
libprotobuf.so.8 => /usr/lib/x86_64-linux-gnu/libprotobuf.so.8
meaning that it is linking against the libraries for v2.5 in /usr/lib/x86_64-linux-gnu, even though I added a hard-coded path to the correct .so file in /usr/lib in the call to target_link_libraries when building this executable.
What is worth noting is that if I remove the .so files in /usr/lib/x86_64-linux-gnu, then it does link against the correct .so file in /usr/lib, so it appears that for some reason, CMake searches in /usr/lib/x86_64-linux-gnu before using the library path that I provide it. How can I change this behavior, or fix this problem in any other way?
UPDATE
The library file for v3.4 /usr/lib/x86_64-linux-gnu/libprotobuf.so is a link to /usr/lib/x86_64-linux-gnu/libprotobuf.so.14 which in turn is a link to the actual file /usr/lib/x86_64-linux-gnu/libprotobuf.so.14.0.0.
Now, if I change the hard-coded path that I give in target_link_libraries from /usr/lib/x86_64-linux-gnu/libprotobuf.so to either the second symlink /usr/lib/x86_64-linux-gnu/libprotobuf.so.14, or to the actual file /usr/lib/x86_64-linux-gnu/libprotobuf.so.14.0.0, then my executable correctly links againt v3.4. It appears that the name of the provided symlink has some effect on CMake's behavior.
This isn't cmake specifically but also how things work on Linux with gcc and shared libraries.
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
When you specify target_link_libraries( target /usr/lib/x86_64-linux-gnu/libprotobuf.so) this sets up linking as -lprotobuf. In this case it should just use any version of the library it finds first.
target_link_libraries( target /usr/lib/x86_64-linux-gnu/libprotobuf.so.14) adjusts the cmake generated link line to use a specific library version. This seems to tell gcc to link against that version which will change what happens at run-time and library searches.
target_link_libraries
There are some cases where CMake may ask the linker to search for the library (e.g. /usr/lib/libfoo.so becomes -lfoo), such as when a shared library is detected to have no SONAME field. See policy CMP0060 for discussion of another case.
I've built the boost (1.56) libraries on a windows (8.1) machine according to the documentation, both as shared and static libraries.
All of them appear in the BOOST_ROOT/stage/lib directory in the following file name format:
boost_thread-vc120-mt-1_56.dll
boost_thread-vc120-mt-1_56.lib
boost_thread-vc120-mt-gd-1_56.dll
boost_thread-vc120-mt-gd-1_56.lib
(this is just the thread lib, the same format is used for all the other libs as well)
When I run cmake it complains about not being able to find the boost libraries.
Running it with -DBoost_DEBUG=ON shows that it looks for different file names:
libboost_thread-vc120-mt-s-1_56;
libboost_thread-vc120-mt-s;
libboost_thread-mt-s-1_56;
libboost_thread-mt-s;
libboost_thread
I noticed the following differences:
The prefix for the actual files is boost and not libboost as cmake is searching for
The static version of the actual files just has a different file extension (.lib instead of .dll) but cmake is looking for -mt-s
Any idea how I can make cmake find the actual files without renaming the files I have to match cmake's search formats?
Thanks
Note: boost_thread-vc120-mt-1_56.lib is an import library allowing dynamic linking with boost_thread-vc120-mt-1_56.dll, while libboost_thread-vc120-mt-s-1_56 is a static library (s letter means it's also statically linked with CRT).
The application you try to build expects static Boost libraries having static CRT, so you should provide them. To build such libraries, invoke b2 with the appropriate parameters:
b2 variant=release link=static runtime-link=static stage
I've been trying to include different types of libraries with CMake.
.a
.dylib
.so
I finally, got both the .a and .dylib to work with this code.
find_library(libname NAMES libcef.dylib PATHS ${libname_PATH})
along with this, underneath where I add_executable to initialize all my files for the build.
target_link_libraries(${PROJECT_NAME} ${libname})
However, I tried using the same code on a .so file and it doesn't seem to work.
I get this statement from cmake when I try building.
Target "project name" links to item
-- path of file --
which is a full-path but not a valid library file name.
I'm not sure if this is the correct way to handle .so files or perhaps I'm not even fully understanding what an .so file is. Any input and/or clarification would be much appreciated.
edit:
THEORY- my theory is because it doesn't have a lib in front of the name of the library name its called ffmpegsumo.so. However, when i try renaming it the file name still saves into the variable name very strange.
The same should work with .so files also, just make sure the required .so file is present at ${libname_PATH} which you have given.
find_library treats all types (.a / .so/ .dylib/ .dll) the same way. Problem may be the following
-- path not set up correctly
-- error because of absolute path
-- .so not present
-- If the error is from build (not from configure only) the .so might be corrupt, try replacing it
--Your library does not seem to be valid
Shared libraries are linked dynamically. That means that your OS will automatically look for and load the .so files when the time comes to run the application. You only need to tell cmake the name of the library and the OS will take care of the rest.
For example, if you want to link to the dynamic library for libSDL.so, you just say: target_link_libraries(${PROJECT_NAME} SDL)
As a sanity check, your linker will look to make sure that the SDL library does exist on your computer. That's why you might get a linking error if that library is not available at link-time, even if it's really a dynamic library.