Missing the Obvious? Linking to Cinder on Linux


#1

I have a bit of a dilemma. We have a project that needs to use Cinder (specifically the audio features). The project is built with CMake, but we need to be able to link to several other libraries, use our own CMake options (which are extensive), and so on. But, just linking to the libcinder.a and the includes isn’t sufficient, since it has other dependencies as well.

If I’m understanding the documentation correctly, the only “easy” way to link to use ci_make_app(), but this appears to imply that we would be using that tool for building our project, thereby preventing our use of our own compiler options, dependencies, etc etc etc. Yet, the alternative is to read through ci_make_app(), and reproduce the complicated Cinder dependency linking ourselves.

Am I missing the obvious, or is that about right?


#2

Hey there,

You don’t need to use ci_make_app(), it is only a utility to simplify setting up a cross-platform windowed application, along with cinder’s concept of add-ons (called ‘CinderBlocks’) and any other common steps (like adding an icon or assets / resources).

Cinder itself is represented as a cmake module, so you can use a regular find_package() to pull it into your existing build setup. You can see how the ci_make_app() function does that here. Note the CINDER_PATH directory, which points to the root folder where you have cinder installed, and also the CINDER_LIB_DIRECTORY; this latter one is constructed per-platform within the configure.cmake file, which you can also include in your project to set various common variables. It basically just defines where within the cinder/lib/ folder to look for libcinder.a and and cinderConfig.cmake.

Hope that helps and let us know how it goes,
Rich


#3

Thank you so much! My assistant lead dev, @atprice, is actually going to be taking over a big part of this task, but I’m sure we’ll both be in here.

Already, your response has made this a thousand times less terrifying than linking to a similar open source library (which shall not be named).

We’ll keep y’all posted.


#4

Thank you for your help @rich.e. We took your advice and am using find_package() as they do in the link you posted (at least we hope we are using it correctly). Once we try #include "cinder/audio/audio.h", we get undefined references to boost.

Here is a snippet of our CMakeLists.txt where we do our includes:

include_directories(${CINDER_DIR}/cinder/include)

We know it is finding it because of the warnings about unused parameters.

This is how we use find_package():

find_package(cinder REQUIRED PATHS ${CINDER_DIR}/cinder/lib/linux/x86_64/ogl/Release)

Finally, this is the error the compiler is giving us:

/home/alex/repos/test/sandbox-source/../../cinder/cinder/include/boost/system/error_code.hpp:221: undefined reference to boost::system::generic_category() /home/alex/repos/test/sandbox-source/../../cinder/cinder/include/boost/system/error_code.hpp:222: undefined reference to boost::system::generic_category() /home/alex/repos/test/sandbox-source/../../cinder/cinder/include/boost/system/error_code.hpp:223: undefined reference to boost::system::system_category()

What are we missing?


#5

Hi,

the idea behind using find_package is that you don’t have to manually specify include or link dependencies but you still need to link with the target that you specified in the find_package command ( in this case the target is cinder ).

What you should do is link your app with Cinder with target_link_libraries( YourApp cinder ) after the call to find_package and this should pull in all include and link dependencies of Cinder. The manual call to include_directories should not be necessary if you do this and also boost should be pulled in and linked properly with your app resolving the linking errors you are currently facing.

Cheers,
Petros


#6

Big help @petros! Thank you, it is working now. Here is the working version:

# Include headers of dependencies.
include_directories(${CPGF_DIR}/include)
include_directories(${EIGEN_DIR}/include)
include_directories(${OPUS_DIR}/include)
include_directories(${PUGIXML_DIR}/include)
include_directories(${PAWLIB_DIR}/include)

add_executable(${TARGET_NAME}
    main.cpp
)

# Link against Cinder and its dependencies.
find_package(cinder REQUIRED PATHS ${CINDER_DIR}/ogl/Release)
target_link_libraries(${TARGET_NAME} cinder)
target_link_libraries(${TARGET_NAME} ${CINDER_DIR}/libboost_filesystem.a)
target_link_libraries(${TARGET_NAME} ${CINDER_DIR}/libboost_system.a)

# Link against other dependencies.
target_link_libraries(${TARGET_NAME} ${PAWLIB_DIR}/lib/libpawlib.a)
target_link_libraries(${TARGET_NAME} ${CPGF_DIR}/lib/libcpgf.a)
target_link_libraries(${TARGET_NAME} ${OPUS_DIR}/lib/libopus.a)
target_link_libraries(${TARGET_NAME} ${PUGIXML_DIR}/lib/libpugixml.a)

The ${CINDER_DIR variable is defined in an external configuration file.

set(CINDER_DIR
	${CMAKE_HOME_DIRECTORY}/../../cinder/cinder/lib/linux/x86_64
)

Are there any improvements you can see?
Cheers, atprice


#7

Hi,

cool that you got it working but here is how I would do it in order to make the whole process a bit more generic :

# Create your application target.
add_executable( ${TARGET_NAME} main.cpp )
# Specify include dependencies for your target.
target_include_directories( ${TARGET_NAME} 
                            PUBLIC 
                            ${CPGF_DIR}/include
                            ${EIGEN_DIR}/include
                            ${OPUS_DIR}/include
                            ${PUGIXML_DIR}/include
                            ${PAWLIB_DIR}/include
                          )
# Get the full path to Cinder's root directory
get_filename_component( CINDER_PATH "${CMAKE_HOME_DIRECTORY}/../../cinder/cinder/" ABSOLUTE )
# Include Cinder's specific configure file which defines some basic variables
# based on the OS, build type etc you are running..
include( "${CINDER_PATH}/proj/cmake/configure.cmake" )
# Pull Cinder's package configuration file. This will pull in all Cinder's include and link dependencies for you.
# ${CINDER_LIB_DIRECTORY} will be pulled in from the above configure.cmake file.
find_package( cinder
              REQUIRED 
              PATHS "${CINDER_PATH}/${CINDER_LIB_DIRECTORY}"
            )

# Link Cinder and your other dependencies with your application.
target_link_libraries( ${TARGET_NAME} 
                       PUBLIC 
                       cinder
                       ${PAWLIB_DIR}/lib/libpawlib.a
                       ${CPGF_DIR}/lib/libcpgf.a
                       ${OPUS_DIR}/lib/libopus.a 
                       ${PUGIXML_DIR}/lib/libpugixml.a
                     )  

As you can see with this version the paths are more generic, no need to manually link with boost ( it’s getting pulled in for you by linking with cinder ) and also it uses the target_* variant for the includes also, since it’s the preferred and recommended way to deal with target dependencies in recent versions of CMake. Your CINDER_PATH variable can be still defined of course in an external config file.

Obviously this is untested and I just mirrored your working configuration but in theory you should be good to go with the above.

HTH,
Petros


#8

Could this be added to the wiki entry for CMake?

I’ve just started to learn Cinder recently and - and magic build functions a-la openFrameworks made me incorrectly assume that using Cinder marries me not just to a library but also a custom build system (like Qt?). I understand the convenience aspect, but it kinda left me with the wrong impression

Just an observation from a new learner :slight_smile:
The flexibility and modularity of Cinder as a library has been absolutely fantastic. I dabbled a bit with oF and definitely didn’t get the same vibe.

Thanks for all the great work. I hope to be able to contribute back eventually


#9

Just a note that if someone would like to update cmake docs, they’ve been moved to html in preparation for 0.9.1 release, so those html versions should be the ones modified by way of pull request.

I think a section on how to integrate cinder into an existing app, without ci_make_app(), would be nice, though I think it makes sense for that to come from someone who has done this. :slight_smile: For myself, while we designed the system around cmake best practices, I only work on cinder projects.

cheers,
Rich