How to use CMake to construct an OpenSceneGraph project? - cmake

I have just downloaded the OpenSceneGraph source, unzip it into
"~/OpenSceneGraph-3.0.1" directory and use CMake to create an out-of-source
eclipse make project in "~/OpenSceneGraph-3.0.1-build-eclipse-cdt"
directory. When I execute "make" in
"~/OpenSceneGraph-3.0.1-build-eclipse-cdt" directory, OpenSceneGraph builds
successfully. I have not run "sudo make install" as I do not want to
install OpenSceneGraph tightly into my Ubuntu system.
Now I want to use CMake to create a project using the compiled
OpenSceneGraph libraries. I use the following codes in CMakeLists.txt :
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT( test_proj )
FIND_PACKAGE(OpenSceneGraph)
ADD_EXECUTABLE(test test.cpp )
INCLUDE_DIRECTORIES(${OPENSCENEGRAPH_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(test ${OPENSCENEGRAPH_LIBRARIES} )
But it seems that OpenSceneGraph could not be found by CMake.
Does anyone know how CMake could find the compiled OpenSceneGraph
libraries in the "~/OpenSceneGraph-3.0.1-build-eclipse-cdt" directory and
use it to create projects as if I have tightly installed OpenSceneGraph
using "sudo make install". Thanks for any suggestion.

You don't need to install OpenSceneGraph system-wide. Just choose a CMAKE_INSTALL_PREFIX that suits you (eg. ~/osg).
Using the install command makes sure that everything is correctly in place (i.e. in the correct directory structure) for FindOpenSceneGraph.cmake (the script CMake invokes when you call FIND_PACKAGE( OpenSceneGraph ) ) to find it.
Then, you should point any of OSG_DIR, OSGDIR, or OSG_ROOT as environment variable and point it to your install location, so CMake knows where to look for it.
Edit:
#Hugues: I'll try to make it a bit clearer:
Setup up OpenSceneGraph:
Get OSG source.
When running CMake for it, choose a CMAKE_INSTALL_PREFIX that suits you, eg. ~/osg if you don't want a system-wide installation in (default) /usr/local. Do it either by stating -DCMAKE_INSTALL_PREFIX=/home/hugues/osg on the command-line or by setting it using a gui tool like ccmake or cmake-gui.
Run make install to build and install OSG.
Set the environment variable OSG_DIR to whatever you pointed CMAKE_INSTALL_PREFIX. (export OSG_DIR=<whereever_you_installed_osg>)
Setup your project:
In your CMakeLists.txt, use FIND_PACKAGE( OpenSceneGraph ) (add desired optional arguments as desired).
Use the resulting variables (like ${OpenSceneGraph_LIBRARIES} in the appropriate places in your cmake file.
Run CMake for your project.

Add this below command in your CMakeLists.txt:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
Then put the file FindOpenSceneGraph.cmake in src/cmake dir.
FindOpenSceneGraph.cmake can be found here.

Related

How to include a library using CMAKE in a cross-platform way

I am trying to use the assimp library in a cross platform C++ project. I include the repo as a git submodule, so, effectively, if someone downloads my project they will also download the ASSIMP project.
After I go through the assimp build / CMAKE instructions and (on Linux) type make install and from then on in my project I can use:
target_link_libraries(${PROJECT_NAME} assimp)
However, there is no make install on Windows.
The only other way I have been able to include the library on Linux is to put (in my CmakeLists.txt file):
target_link_libraries(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/build/assimp/code/libassimp.so)
This is not cross platform as it hardcodes the name and location of the .so file which will not work on Windows.
How can I expose the library so that I can do something like target_link_libraries(${PROJECT_NAME} assimp) on all platforms?
My directory tree looks like:
- src
- include
- assimp
- bin
Where the assimp directory in the include directory is the git submodule
I think you're going about this the wrong way. You don't need to build assimp in a separate step from your project, and you don't need to make install to make it available.
There are a number of ways of handling third party dependencies in Cmake, since you've already chosen to submodule the assimp repository, we'll start there. Assuming assimp is located in the root of your repository in a directory called assimp/ this would be a barebones project including it:
cmake_minimum_required(VERSION 3.0)
project(Project myassimpproj)
# include your directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
# set any variables you might need to set for your app and assimp
set(BUILD_ASSIMP_TOOLS ON)
set(ASSIMP_BUILD_STATIC_LIB ON)
# add assimp source dir as a subdirectory, effectively making
# assimp's CMakeLists.txt part of your build
add_subdirectory(/path/to/assimp ${CMAKE_BINARY_DIR}/assimp)
add_executable(assimp_target main.cpp)
# be sure to link in assimp, use platform-agnostic syntax for the linker
target_link_libraries(assimp_target assimp)
There may be a better way of phrasing this using generator expressions syntax, but I haven't looked at assimp's CMakeLists.txt to know if it's supported (and this is a more generic way anyway.)
Not every project uses Cmake, so you may not be able to just add_subdirectory(). In those cases, you can effectively "fake" a user call to build them using their build commands on respective platforms. execute_process() runs a command at configure time add_custom_command() and add_custom_target() run commands at build time. You then create a fake target to make integration and cross your fingers they support Cmake someday.
You can also use the ExternalProject commands added to Cmake to create a custom target to drive download, update/patch, configure, build, install and test steps of an external project, but note that this solution and the next download the dependency rather than using the submodule'd source code.
Finally, I prefer to work with prebuilt dependencies, cuts down on build time, and they can be unit tested on their own outside of the project. Conan is an open source, decentralized and multi-platform package manager with very good support for C++ and almost transparent support for Cmake when used the right way. They have grown very stable in the last year. More information on how to use Conan with Cmake can be found here.

CMake find protobuf compiled from source

I am trying to build a project that depends on Google Protocol Buffers compiled from source. My project should be platform independent and also should support cross-compilation, which is the reason that i prefer to use a locally built protobuf. However I would prefer not to include the whole library as a subproject as it would take too much to build.
My simplified CMakeLists.txt is:
cmake_minimum_required(VERSION 3.5)
project(sample-protobuf)
# find a boost install with the libraries filesystem and system
find_package(Protobuf REQUIRED)
set(SOURCES
main.cpp
)
add_executable(sample
${SOURCES}
)
target_link_libraries(sample
PRIVATE
protobuf::libprotobuf
)
I invoke CMake on Linux as:
cmake -DCMAKE_PREFIX_PATH=/path/to/built/protobuf/ ..
but it does not find the library and I get the following message:
Could not find a package configuration file provided by "Protobuf" with any
of the following names:
ProtobufConfig.cmake
protobuf-config.cmake
Add the installation prefix of "Protobuf" to CMAKE_PREFIX_PATH or set
"Protobuf_DIR" to a directory containing one of the above files. If
"Protobuf" provides a separate development package or SDK, be sure it has
been installed.
On Windows this procedure works.
I built the library on Linux using the suggested approach, which is not with CMake but with autotools.
What should I do differently?
cd protobuf/cmake
mkdir build
cd build
cmake....
make...
sudo make install

cpack cmake windows "ABSOLUTE path INSTALL DESTINATION forbidden"

I am trying to use cpack with cmake and nsis to generate an installer which add the .exe files generated to the environment variable.
I have a main cmakelist.txt
in which I add subdirectory with add_subdirectory( each subdirectory has a cmakelist.txt.
in the main subdirectory at the end for now I added:
SET(CPACK_NSIS_MODIFY_PATH ON)
SET(CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION OFF)
INCLUDE(CPack)
and in each "sub"cmakelist.txt
I added :
SET(CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION OFF)
INCLUDE(CPack)
I have this error:
CPack: Create package using NSIS
CPack: Install projects
CPack: - Install project: MIALSRTK
CMake Error at D:... ABSOLUTE path INSTALL DESTINATION forbidden (by caller):
(this is why I tried: SET(CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION OFF) but it hasn't change anything).
I tried to run as administrator as well.
I also tried the solution here: CPack NSIS, generate installer for Windows
but if(pack) doesn't seem to works. it goes into the else(pack) part (i used the command message to see where it goes).
Do you have any idea on how to solve this problem ?
Setting variable CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION to OFF cannot disable checking for NSIS CPack generator:
Some CPack generators, like NSIS, enforce this internally.
With NSIS generator you have no other way than using relative install paths.
Construction if(pack) will work only if you pass pack variable explicitly to cmake. There is no implicit way for CMakeLists.txt to detect, whether it is run under CPack.

cmake: install executables and create links to them

I'm using cmake and cpack to build my project and build packages. I'm creating a few executables in my project, let's call them EXE1 and EXE2.
When creating different versions of these executables, I want to name to reflect the version of the executable (let's say EXE1_1.0.0). I can change the name of the output for a target by doing set_target_properties.
However, now when doing an install, I want to do create a symlink to this versioned name of the executable, i.e. I want to have
the "versioned" executable installed in bin directory, i.e. EXE1_1.0.0
create a symlink to the "versioned" executable, i.e. create symlink EXE1, which points to EXE1_1.0.0
Can someone suggest me how to do this?
Second question is:
How to install configuration files /etc/MYPROJECT/ directory? What DESTINATION I need to use for configuration files, like I use bin for executables and lib for libraries? Is using an absolute path like /etc an acceptable practice with cmake?
I asked this question on cmake mailing list subsequently, and this is the response I received:
The validity of the answer will depend on which CMake version you use
and which set of platform you want to support.
Symlinks are not that portable
a) Creation may not be [currently] done portably but if you are
targeting Unix you can use cmake -E create_symlink to create one.
b) Depending on the CPack generator you use and CMake/CPack version
symlinks may be embedded in the package or not.
i.e. CPack pre 2.8.7 cannot create ZIP archive which contains
symlinks CPack 2.8.8 can do that now.
Then you can use an install(SCRIPT ... or install(CODE ...) to do that
at install time.
Another option if you are using RPM is to use package specific post
install script. cpack --help-variable
CPACK_RPM_POST_INSTALL_SCRIPT_FILE
this last solution will off course only work for CPack RPM.
For second question
You can use absolute destination path, they should be handled just
fine by CPack DEB and RPM, I don't know for other.
If your software should be installed on Windows this is won't work
with archive generator (ZIP, TGZ, etc...) and/or NSIS.
May be you can do something like:
if(UNIX AND NOT APPLE) set(CONFDEST "/etc/${CMAKE_PROJECT_NAME}")
else() set(CONFDEST "etc") endif()
install(FILES yourconffile DESTINATION ${CONFDEST})

Use external DLL in cmake build

I'm working on the cmake scripts for my project and I've run into a problem:
My project uses a 3rd party library (FreeImage), which has its own Makefile-based build system. I can build FreeImage just fine by simply running "make" (I'm using gnuwin32), which will build FreeImage using MinGW and produce:
FreeImage.lib
FreeImage.dll
Now my problem is twofold:
I want to execute "make" from my cmake script.
I want to link to the import lib (FreeImage.lib), and also make sure the DLL gets copied to the correct place so the EXE will run.
I know how to link to the LIB file, but I'm lost on the rest.
The folder structure is like this:
MyProject # main directory
MyProject/Libs/FreeImage # FreeImage root directory
MyProject/Libs/FreeImage/Dist # This is where FreeImage outputs go (LIB and DLL)
BTW: I'm running on Windows 7. I plan to build my project both with MSVC and MinGW.
Thanks!
EDIT:
I'm now trying to use ExternalProject_Add like so:
ExternalProject_Add(
FreeImage
PREFIX ./Libs/FreeImage
URL ./Libs/FreeImage
BUILD_COMMAND make
)
This gets me part of the way there, but doesn't totally work... it tries to configure things for me and tries to use nmake... ugh
In my opinion, there are two options:
In case you have put your FreeImage sources in your projects' source-tree, the easiest option may be to use the execute_process() command. Assuming FreeImage is in your projects' source-tree in "3rdparty/FreeImage/" you can do something like,
execute_process( COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage )
Optionally, you can copy the dll from 3rdParty/FreeImage/bin into you own bin directory. And then you can write a FreeImageConfig.cmake for importing the library:
add_library( FreeImage IMPORTED )
set_target_properties( FreeImage PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage/lib )
...
The other option is to make use of the ExternalProject module. You can also take a look at this article from Kitware for an overview of this module. In essence, you specify the full chain of commands needed to get the source, configure the build, build the source and install it. All in your own CMakeLists.txt