Reputation: 788
I need to use OpenGL as a library in my project on my Ubuntu 15.04 64bit PC, which is built by CMake 3.0.2. I install packages: mesa-common-dev mesa-utils-extra libgl1-mesa-dev libglu1-mesa-dev libglapi-mesa libx11-dev libxi-dev libxinerama-dev libxcursor-dev libxrandr-dev
After run cmake and Makefile, I got these link error:
/usr/bin/ld: /home/user/CMU462/DrawSVG/asst1_drawsvg/lib/libglfw.a(x11_window.c.o): undefined reference to symbol 'XConvertSelection'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libX11.so: error adding symbols: DSO missing from command line
I checked /usr/lib/x86_64-linux-gnu/libX11.so
, it does exist.
I found a explanation, it seems I failed to link my project with X11 library. The answer says that add -lX11
option may fix this.
Alternatively I link
X11 library in CMakeLists.txt
according to FindX11.cmake:
find_package(X11 REQUIRED)
message(STATUS "X11_FOUND = ${X11_FOUND}")
message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}")
message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}")
include_directories(${X11_INCLUDE_DIR})
link_directories(${X11_LIBRARIES})
target_link_libraries(MyProj ... ${X11_LIBRARIES})
Run cmake I got these output:
-- X11_FOUND = 1
-- X11_INCLUDE_DIR = /usr/include
-- X11_LIBRARIES = /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so
But I still got the error aforementioned.
QUESTION: The X11 library can be linked by
target_link_libraries
in CMakeLists.txt
, or -lX11
option directly to compiling commandWhat's the difference between them? Does the link in CMakeLists.txt
directly lead to a -lX11
option in Makefile
generated?
If so, did I do something wrong in CMakeLists.txt
?
UPDATE
Let's take this project as example, following is my build procedure.
Install required libraries: Install the OpenGL and other relative libraries (the GLEW and GLFW library is provided in this project): mesa-common-dev mesa-utils-extra libgl1-mesa-dev libglu1-mesa-dev libglapi-mesa libxi-dev libxinerama-dev libxcursor-dev libxrandr-dev
Run CMake: Then use the provided CMakeLists.txt
, everything goes right.
Make: When make the project, this error occurred:
/usr/bin/ld: /home/user/CMU462/DrawSVG/asst1_drawsvg/lib/libglfw.a(x11_window.c.o): undefined reference to symbol 'XConvertSelection'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libX11.so: error adding symbols: DSO missing from command line
I have searched for many times, all of the answers say that the incorrect link of glfw3 and x11 lead to the error:
-X11
option. However in line 26 of CMakeLists.txt
exists this optionpkg-config --libs
command, all libraries are arranged in order in line 17 to 29 of CMakeLists.txt
.The only potential reason for this is the order of the compile options of libraries (line 17 to 29) and the target_link_libraries
(line 116) of CMakeLists.txt
.
Otherwise, there must be another error omitted by me during my procedure.
Upvotes: 2
Views: 10360
Reputation: 20798
Here are a few huge differences between using CMake to find libraries and directly doing something like -lX11
:
When looking for a library with cmake ...
you can use the REQUIRED
flag. This means if the library cannot be located on your development or build system, the process stops here in a much clearer manner than if you tried to compile and get errors for failing #include
or linking against non-existing libraries.
For example:
find_package(Boost REQUIRED)
The find_package()
is expected to be provided by the author of a given package (CMake also provides some of <name>.cmake
files). This is very helpful as the author knows where they install the headers. This can change drastically between operating systems (even different versions of Linux).
As a results you get a variable set with the path to the library.
target_include_directories(${PROJECT_NAME}
PUBLIC
${Boost_INCLUDE_DIRS}
)
Again, you may not see that as super useful. After all, all includes are under /usr/include
, right? In one of my projects, I have 30 contribs. Each one installs files under directory ${CMAKE_BINARY_DIR}/dist/include
. For me to have those headers accessible by the other contribs and the main system, I have to have CMake find those files and give me the correct path. I definitely could hard code that path too. After all, that dist/include
is the same thing as /usr/include
... however, yet again, the user could decide to move that folder somewhere else. The CMake approach helps you dealing with many such situations.
The next step, as you asked about the -lX11
and whether the target_link_libraries()
is of any help, is to determine how to link the library.
To link against all the Boost library you use the following:
target_link_libraries(${PROJECT_NAME}
${Boost_LIBRARIES}
)
If you only want to link against a specific Boost library, then you can use that specific component name:
target_link_libraries(${PROJECT_NAME}
${Boost_FILESYSTEM_LIBRARIES}
)
Note that the include may also require the special component name.
99% of the time, libraries can be linked using the -l<name>
option. Here we have several issues. The CMake search will find the library in a location which may not be /usr/lib
. Actually, on Linux, we now have /usr/lib/x86_64-linux-gnu
, although the linker knows about that one, there could be other sub-directories and other locations (/lib
) that some OSes use. CMake is likely to find those automatically.
Actually, in many cases, the full path is used instead of the usual -l
. Some CMake libraries may instead make use of the -L
command line option. Further, some libraries have special command line option requirements. These will also be gathered by CMake and added to various variables that you can make use of (usually named after LDFLAGS
).
Yes.
The compile step may require special CFLAGS
or CXXFLAGS
. I think this is pretty rare these days, but I've seen some libraries requiring really complicated compilation flags (i.e. -DNAME=...
). These are added to a library specific set of flags that you can add to your CFLAGS
and/or CXXFLAGS
(in most cases, these are not made mandatory as they can have unwanted side effects).
So, as a conclusion, if -lX11
works for you and you don't want to spend any time on the corresponding CMake implementation, you can always use -lX11
. If you want many people out there to be able to compile your project, though, you'll want to setup CMake properly and use all of those parameters in your project. Then a much larger number of people will be able to use your software.
As mentioned by others, the link_directories()
is to add directories to the linker. These are added using the -L
command line option. This is rarely used manually. In most cases, the full path to the library is used by CMake allowing the library to be really anywhere (like in my case, my libraries end up under dist/lib
).
Upvotes: 0