Cmake: link openscenegraph to my shared library - c++

I'm new in using CMake, and I need to link openscenegraph library to my shared library.
Part of code responsible for it looks like this:
add_library (MyLib SHARED ${${PROJECT_NAME}_sources})
target_link_libraries(MyLib ${OPENSCENEGRAPH_LIBRARIES})
Im finding osg like this:
find_package(OpenSceneGraph REQUIRED osgDB osgUtil osg osgViewer osgGA osgShadow)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
add_definitions(${OPENSCENEGRAPH_DEFINITIONS})
And everything looks like it is linking, CMake isn't giving me any errors, but during building with Visual Studio 2010 I got errors like:
fatal error C1083: Cannot open include file: 'osg/Node': No such file or directory
Usually I was finding answers to all my questions without asking them (this is my first question here).
This may be trivial, but can someone tell me what am I doing wrong, and how can I make it work?

This doesn't seems related to linking, but to compile. The error says that MSVC doesn't find the file 'osg/Node' in the list of included directories.
Somewhere in your source code, you probably have an include like
#include "osg/Node"
so compiler will search for a file called 'Node' in the directory called 'osg' in one of the 'include directories'.
In CMake, print the list of include dirs for OpenSceneGraph (after find_package(OpenSceneGraph ...)
message(STATUS "OSG Incl dirs: ${OPENSCENEGRAPH_INCLUDE_DIRS}")
then check this list. If it contains something like C:/path/to/openscenegraph/include then you should import Node using
#include "osg/Node"
If instead you have a folder for each module (ex: C:/path/to/openscenegraph/include/osg) so you must use
#include "Node"
If you don't want to modify includes in your code, then you have to add C:/path/to/openscenegraph/include in your include directories (from CMake script)
include_directories(C:/path/to/openscenegraph/include)

Related

What's the difference between passing a "xxx.a" file and a target to target_link_libraries()?

When I pass a target to target_link_libraries(), it worked fine.
But when I pass a .a file (the "worked fine target" produced), it worked fine while compiling but produced many errors while linking.
I have a project, and the CMakeFiles.txt is like this:
file (sources a.cc b.cc ...)
add_executable(my_project ${sources})
Now I want to produce a static library using the same source files to support another project.
So the CMakeFiles.txt is like this:
file (sources a.cc b.cc ...)
add_library(my_project ${sources})
add_executable(another_project main.cc)
target_link_libraries(another_project my_project)
It works fine, But when I try to link .a file directly like this
target_link_libraries(another_project libmy_project.a)
And it produced lots of "undefined reference to" or "multiple defination to" error when linking the target.
So what exactly happen when pass a target to "target_link_libraries"?
First, if you link the target against a file, you should first ensure this file exists before linking happens, thus you should add target dependencies between the executable and library targets (provided both are part of the same CMake project)
add_dependencies(another_project my_project)
Second, if you link against an arbitrary file (which is not any of the system libraries), you are supposed either provide full path to the file:
target_link_libraries(another_project ${CMAKE_CURRENT_BINARY_DIR}/libmy_project.a)
Or add the folder where the library is located to the current library search directories list:
link_directories(${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(another_project libmy_project.a)
So what exactly happen when pass a target to "target_link_libraries"?
Simply put, when CMake hits a reference to a library in a form of libName.a, it just adds -lName flag and lets the linker locate the library itself. The linker then fails, because it looks for corresponding archives under LIBRARY_PATH paths only by default.

C++ - Why is a Static Library unusable without source files?

So from what I understand, a static compiled mylib.a file should just be usable as plug-and-play. But I can't use it without the source code, I'm trying to avoid that.
I adapted this tutorial to compile using CMake with the following directory structure:
/
lib
libmy_math.a
main.cpp
my_math.h
my_math.cpp
CMakeLists.txt
The contents of the files are exactly as in the tutorial. The only added file is CMakeLists.txt which basically just runs the library compiling part before building:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(Test)
### Uncomment this ONCE to compile a libmy_math.a file
# add_library(my_math STATIC my_math.cpp)
add_executable(Test main.cpp)
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
As the CMake file says, uncommenting Line 5 compiles the library, which is then linked to my code when compiling.
I'm trying to package my code so that I don't show my client the source code for the compiled library (my_math), but if I delete the my_math.h and my_math.cpp files, I get a "file not found" error on import:
/Users/Joe/Desktop/Test/main.cpp:1:10: fatal error: 'my_math.h' file not found
#include "my_math.h"
^~~~~~~~~~~
I thought you could compile libraries without needing the source code. What am I missing here?
A static library does not contain each and every definition a header can contain - think of macros, etc. Thus you still need the header. However, you don't need the .cpp anymore to link the library.
Besides the problem stated in Iorro's answer the find_library call here will not work as expected.
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
What this does is, while running CMake, look for the my_math.a file. However, at that point of the build process, my_math.a has not been built yet. You're just running CMake for the first time, so all you have is source files. Nothing has been compiled yet.
What you want to do instead is link to the library target directly, as CMake already knows about that and can resolve the dependency on its own. So you need to replace the two lines above with:
target_link_libraries(Test PUBLIC my_math)
This now introduces a curious asymmetry in how your test consumes the library (as it is part of the same build) vs. how your clients consume the same library (which are not part of the same build and thus need to do a find_package call before they can use it). Look at CMake's config-file packages for a mechanism that allows you to restore symmetry here, at the cost of a significant amount of boilerplate required in your CMake script.

CMAKE not finding GUROBI external library

I am new to CPP, to GUROBI and specially to CMAKE. I am working on a project and I am trying to compile a C++ program, that needs to link to the GUROBI external libraries libgurobi81.so and libgurobi_c++.a as explained in the GUROBI site here and here.
The structure of my cmake and my project is something like this:
-folder1
--src
---cmake
--gurobi
---lib
----libgurobi81.so
----libgurobi_c++.a
My code compiles correctly, but it only fails when linking with the libraries.
I tried to make CMAKE to find the libraries:
find_library(C_GUROBI_LIB NAMES libgurobi81.so gurobi81 gurobi81_light
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/gurobi/lib/
)
find_library(CPP_GUROBI_LIB NAMES gurobi_c++
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/folder1/gurobi/lib/
)
and then to print it:
message("C_GUROBI_LIB points to " ${C_GUROBI_LIB})
message("CPP_GUROBI_LIB points to " ${CPP_GUROBI_LIB})
However, even if the library is in that folder CMAKE do not find it and shows nothing:
C_GUROBI_LIB points to
CPP_GUROBI_LIB points to
I found a possible solution, adapted from here:
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
I had some other issues, for example the library was compiled for 64 bits, and also that CMAKE did not allow to add Shared files. So I got to change some parameters, but even with that, CMAKE did not found the file.

In CLion, header only library: file "does not belong to any project target, code insight features might not work properly"

I have a header-only library project set up with the cmake command:
add_library(my_library INTERFACE)
and I also added
target_sources(my_library INTERFACE ${MY_LIRBARY_HEADER_FILES})
but when I open a source file, I get the warning:
This file does not belong to any project target, code insight features might not work properly
and I lose a lot of the functionality on things like code completion.
What is the proper way to set this up so CLion provides its usual functionality on a header-only library?
Little background
I was having the same problem, albeit the project was not header-only, nevertheless, the open files from inc folder were throwing the aforementioned warning, even though the CMake file clearly marked that folder to be include_directory.
*.hpp files do not belong to ${SOURCE}
include_directories("${PROJECT_SOURCE_DIR}/inc/")
add_subdirectory(src)
add_executable(${EXECUTABLE_NAME} main.cpp ${SOURCE})
Since this is a perfectly valid CMake file and adding the include files to source files is not idiomatic, I did not want to amend the CMake file.
The solution
As described on the official JetBrains Forum, the CMake file is indeed valid and the warning is shown because of the inability of CLion to properly index header files. The suggested workaround extracted from the link is to right-click the folder and Mark directory as | Library Files/Project Sources and Headers.
So, this header isn't includes in executables and CLion notifies you that some code insight features might not work properly. As workaround you can use "Mark directory as" Library Files/Project Source and Headers for folder.
Clion takes information about source files from CMake build system. When you add any cpp file to sources list CMake automatically tell about header with same name. So if cpp/h names differs (or you don't have cpp file at all) you should include header manually.
set(Sources my_lib.cpp)
set(Headers header_of_my_lib.h)
add_executable(superlib ${Sources} ${Headers})
If you don't have any executable you can omit last line, CLion will still know about files
This warning is an IDE issue that Android Studio cannot recognise the current directory if it does not include any source files.
Workaround
Adding am empty source file, e.g empty_xxx.c under the directory in question and adding below line in your corresponding CMakeList.txt
add_library(${TARGET_NAME_XXX} SHARED ${SOME_DIR_HAVING_THIS_WARNING}/empty_xxx.c)
will help get rid of this warning.
You can add the header files to your project like this:
set(SOURCE_FILES main.cpp MyClass1.cpp MyClass1.h MyClass2.cpp MyClass2.h)
You can also set it in multiple steps like so:
set(SOURCE_FILES main.cpp)
set(SOURCE_FILES ${SOURCE_FILES} MyClass1.cpp MyClass1.h)
set(SOURCE_FILES ${SOURCE_FILES} MyClass2.cpp MyClass2.h)
Though as mentioned in the comments, you probably shouldn't be adding the header files to your project at all.

CMake adding a library

I am currently simply trying to add a library to one of the example for VTK.
So let's imagine we have this scenario in which I want to redefine the behavior or the trackball. What I did in that is to create my own trackball (based on the model provided by vtkInteractorStyleTrackballCamera). So I created two files: InteractorStyleTrackballCamera.cpp and InteractorStyleTrackballCamera.h
When I CMake, everything is just fine. However when I open the solution with Visual Studio 2013 and try to build the all_build target I get an error stating:
InteractorStyleTrackballCamera.h no such file or directory.
I know of course what it means, however I cannot understand why I get this error. It may be that my CMakeLists.txt is kind of broken (it is the only thing I can think of), so here it is:
cmake_minimum_required(VERSION 2.8)
PROJECT(TrackballCamera)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(TrackballCamera MACOSX_BUNDLE TrackballCamera)
add_library(InteractorStyleTrackballCamera InteractorStyleTrackballCamera.cpp InteractorStyleTrackballCamera.h)
if(VTK_LIBRARIES)
target_link_libraries(TrackballCamera ${VTK_LIBRARIES})
else()
target_link_libraries(TrackballCamera vtkHybrid vtkWidgets InteractorStyleTrackballCamera)
endif()
When I look at my solution explorer in VS13 I can clearly see 4 solutions, ALL_BUILD, InteractorStyleTrackballCamera (with the header and cpp) TrackballCamera and ZERO_CHECK. So that's what is puzzling me. Isn't it right that if the header is included in my solution explorer it should be found when I try to build ?
Oh and if you wonder what's inside my InteractorStyleTrackballCamera (not sure this is really relevant for that problem) I simply copied/pasted the content of vtkInteractorStyleTrackballCamera and replaced all the vtkInteractorStyleTrackballCamera by InteractorStyleTrackballCamera
Thanks in advance for the help.
EDIT: The error does not come from the file InteractorStyleTrackballCamera.cpp but from the file TrackballCamera.cxx when I try to include my header.
Basically the line is:
#include <InteractorStyleTrackballCamera.h>
I see the question has been answered. In addition, have a read of the documentation of
target_include_directories
https://cmake.org/cmake/help/v3.3/command/target_include_directories.html#command:target_include_directories
In CMAKE, you can imbue a target with properties that it carries forward into targets that depend on it. One such properties is the "include directories". This property is different in the following 3 scenarios:
Your target is itself being built
Your target is in the same project as the dependency
Your target has been installed and is being picked up with find_package
target_include_directories allows you to set the correct paths in all 3 cases.
see also target_link_libraries which can be used to ensure that libraries that your library depends on are pulled into any dependent target.
Confused yet? It took me months to get my head around this. Once I did, I realised how incredibly powerful CMAKE is.
#include <...> should only be used for including library headers. If you want to include a header file from your source directory, use #include "...".
With most compilers, the difference is that #include "..." also searches the source file's directory for the file to include, while #include <...> only searches include directories specified on the compiler's command-line (plus possibly some default ones).
Unrelated to the original question, but it seems to me you should link InteractorStyleTrackballCamera even when VTK_LIBRARIES is defined:
if(VTK_LIBRARIES)
target_link_libraries(TrackballCamera InteractorStyleTrackballCamera ${VTK_LIBRARIES})
else()
target_link_libraries(TrackballCamera vtkHybrid vtkWidgets InteractorStyleTrackballCamera)
endif()