Giter Site home page Giter Site logo

how-to-export-cpp-library's Introduction

๐Ÿ“š How to export C++ library

This repository provides an OS-agnostic C++ library template with plain CMake files with the following features:

Overview

๐Ÿ’ข Complexities around C++ library

This project simplifies the process of taking a bunch of C++ classes/functions and exposing them as a CMake package so that third-party code can use it. However, the risk is that new users underestimate the actual complexity of maintaining a C++ library used by many external users!

A complete and proper training on the art and craft of C++ library maintenance is out of the scope of this project, but we feel that we should at least report some useful link to drive the curiosity and the attention of new users to topics relevant to a proper maintenence of a C++ library.

Problems typically overlooked by new C++ library developers:

๐Ÿ… CI and badges

Awesomness Github Actions
Awesome GitHub Actions status

Go to the top

๐ŸŽ› Dependencies

There are no dependencies for this template. However, we make use of the following three files from the YCM project.

  1. AddInstallRPATHSupport
  2. AddUninstallTarget
  3. InstallBasicPackageFiles

These files can be found under ./cmake subdirectory and they are plain CMake code. Check them out, they make your life easier!

If you like the YCM project and it is not a problem to have it as a dependency, updating the template is as simple as follows.

  1. Install YCM
  2. Add find(YCM REQUIRED) in the main CMakeLists.txt, after the project() command.
  3. Delete/Empty the ./cmake folder.

You are now 100% good to go! ๐ŸŽ‰

Go to the top

๐Ÿ”จ Build the libraries

If your shell environment supports mkdir, you can just execute the following commands:

git clone https://github.com/robotology/how-to-export-cpp-library.git
cd how-to-export-cpp-library
mkdir build && cd build
cmake ..
cmake --build .

You can also create platform specific input files for a native build system using CMake Generator.

For more detailed example, check the CGold section on Generate native tool files.

Go to the top

โœ‚๏ธ Copy and customize this template

For customizing the CMake/C++ code, check the comments in the main CMakeLists.txt.

To enable Continuous Integration (CI) using Travis (Linux and macOS) and AppVeyor (Windows) follow the documentation of these services to create an account and connect them to your repository.

Once you're done with that, you can easily modify the appveyor.yml and travis.yml to account changes for your project, such as the project name from how-to-export-cpp-library (the name of the git repository) and LibTemplateCMake (the name of the CMake Project/Package) to the one of your repository/project.

Go to the top

๐Ÿ”ฌ Add a test

This snippet from test/CMakeLists.txt shows the fundamental commands to add a test:

add_executable(test_name_exec test_name_exec_source.cpp)
target_link_libraries(test_name_exec lib-template-cmake)
add_test(NAME test_name COMMAND test_name_exec)

A single test is just a simple C++ executable with an int main() function that returns 0 on success and any value different from 0 upon failure.

For more info on this topic and related CMake commands, check add_test documentation and references therein.

Go to the top

๐Ÿ› Run the tests

If you want to run tests, compile the library enabling the BUILD_TESTING CMake option. Once you do that, test will be compiled along with the library and any other executable in the project.

To list the compiled/available tests, run ctest -N in the build directory. To run the tests, use ctest command in the build directory, while to run a single test, us ctest -R test_name. You can add -VV to get a full verbose output during tests.

For more info and options with ctest, check the ctest documentation.

Go to the top

๐Ÿ“ Generate documentation

If the Doxygen tool is installed on your machine, the Doxygen documentation for the project can be generated using the dox target, see doc/CMakeLists.txt for details on the process of documents generation. Once generated, the doxygen documentation can be browsed at build/doc/html/index.html. If the documentation is generated, it will be installed in ${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME}/html/. The build and installation directories for the doxygen documentation can be changed using the DOXYGEN_BUILD_DIR and DOXYGEN_INSTALL_DIR CMake variables.

If you are interested on how to host your documentation using gh-pages, robotology/how-to-document-modules contains a detailed (and maintained) example on how to produce and host Doxygen documentation using GitHub gh-pages.

Go to the top

๐Ÿ“‘ Licensing your library

The project as-is comes with two files:

  1. LICENSE
  2. LICENSE-template

The first file, LICENSE, is the one covering this very template. You have to modify/delete it. โš ๏ธ Don't use it straightforwardly as it includes our name, not yours!

The second file, LICENSE-template, is an MIT License template that you can use adding the year and copyright holder names in the heading. We provide template of the MIT License as it is the one used for this template, but you can choose one of the many available.

Should you not be sure what to do about it (licensing produces severe headhaces) you can use one of the following website to clear your mind:

Go to the top

๐Ÿ’ผ Other template and examples

The Awesome CMake repository contains an interesting list of template and examples similar to this one.

Go to the top


If you feel this CMake project template was useful, consider starring the project!
We also created the following shield to provide a nice-looking link to this project (feel free to modify its look-and-feel as you please).
Otherwise, not a big deal! ๐Ÿ‘

how-to-export-cpp-library

how-to-export-cpp-library's People

Contributors

claudiofantacci avatar diegoferigo avatar drdanz avatar francesco-romano avatar giuliavezzani avatar pattacini avatar traversaro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

how-to-export-cpp-library's Issues

Branch cleanup

After having pushed the new version on master, should we delete fix-appvayour, fix-appvayour-msi and fix-appvayour-msi2 branches?

Change repository name

After a major update of the repository (see branch master and branch NoYCM), I'm bringing back to your attention the discussion about the repository name.

Name proposed so far:

  • how-to-code-cpp-library
  • how-to-export-library
  • how-to-export-cpp-library
  • how-to-export-cpp-library-template

Here are some template names from Awesome CMake repository.
As far as these ones are concerned, I reckon one of either how-to-export-cpp-library or how-to-export-cpp-library-template is the more appropriate/catchy!

CMake > 3.11 and YCM dependency

The current README, for what concerns the YCM dependency, recommends either vendoring the three files we require, or installing YCM externally.

Starting from CMake 3.11, as many of you already know well, a new FetchContent module was introduced. It allows downloading and configuring external projects during the configuration phase of the project (contrarily to ExternalProject). Therefore, it is an excellent solution for dependencies like YCM.

We should add in the README also this option. Sadly, the default CMake version on the current Ubuntu 18.04 LTS is still 3.10 though.

For a minimal example you can refer to the following implementation:

cc @traversaro @claudiofantacci @pattacini @drdanz

Add instructions on how to create a dox target to generate doxygen documentation

Examples:

Feature that would be useful to support:

  • Generate documentation even without configuring the complete project (useful to generate documentation even if the dependencies of the project are not available)

Avoid setting CMAKE_CXX_STANDARD explicitly in libraries

In abseil/abseil-cpp#259 (comment) , a good point is made against setting CMAKE_CXX_STANDARD explicitly in libraries, in favor of just using target_compile_features(mylib PUBLIC cxx_std_11) to specify the minimum required standard language to compile.
We never set the CMAKE_CXX_STANDARD in this tutorial, but as the use of setting CMAKE_CXX_STANDARD is widespread in robotology libraries, it would be good to have one point where we discuss this. Requiring CMake 3.10 would be a good occasion to switch to use target_compile_features(mylib PUBLIC cxx_std_11).

Provide hints and useful links on the complexity of mantaining a C++ library

This tutorial simplifies the process of taking a bunch of C++ classes/functions and expose them as a CMake package, such that third-party code can use it. However, the risk is that new users underestimate the actual complexity of maintaining a C++ library used by many external users.

A complete and proper training on the art and craft of C++ library maintenance is out of the scope of this repo, but we should at least add a readme section on this, with possibly some useful links.

Problems typically overlooked by new C++ library developers:

  • API backward compatibility (as in: be clear about what you promise to users)
  • ABI backward compatibility (as in: be clear about what you promise to users)
  • Version handling (semver?)
  • Release process
  • Etc/etc

Option to disable install rpath

In the template, we recommend to add a new option ENABLE_RPATH to control whether or not enable rpath on the installation binaries : https://github.com/robotology/how-to-export-cpp-library/blob/master/CMakeLists.txt#L57 .

I noticed that now YARP deprecated the option for doing that, and instead is using the CMake existing option CMAKE_SKIP_INSTALL_RPATH to control if enabling installation rpath https://github.com/robotology/yarp/blob/eeeb98345d528ef56187b06c3712fdd66fadeb08/doc/installation/install_linux.dox#L165 . Using an already existing CMake variable seems to be a good idea.
I propose to do the same here, but listing CMAKE_SKIP_INSTALL_RPATH explicitly as an option like we do with BUILD_SHARED_LIBS and BUILD_TESTING.

How to handle static variables in shared libraries in Windows

I noticed that we did not mention how to handle static variables in shared libraries in Windows. Unfortunately those are not handled by CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS. While the blog post that we link in the README mention that, I wonder if we should stress this more, or we can simply ignore this relatively niche use case. See ms-iot/ROSOnWindows#33 and ms-iot/ROSOnWindows#37 for a related discussion.

Originally posted by @traversaro in #36 (comment)

Any way to modify this for header only libraries ?

Not really header only, but just lot of header files and no target. I tried add_library(${LIBRARY_TARGET_NAME} INTERFACE)

but I can't do

set_target_properties(${LIBRARY_TARGET_NAME} PROPERTIES VERSION       ${${PROJECT_NAME}_VERSION}
                                                        PUBLIC_HEADER "${${LIBRARY_TARGET_NAME}_HDR}")

I can't set the PUBLIC_HEADER property so none of the header files are being installed.

Add C to project LANGUAGES argument?

In https://github.com/robotology/how-to-export-cpp-library/blob/master/CMakeLists.txt#L26 we only list CXX in the LANGUAGES argument of the project call. This was done because this template is meant to show how to build a C++ library using CMake.

However, in the past we had problems with some Find<package>.cmake scripts that required the C language to be enabled, see for example https://bitbucket.org/ignitionrobotics/ign-cmake/pull-requests/44/fix-findfreeimagecmake-compatibility-with/diff .

Recently, we had the same problem with the FindHDF5.cmake with @pattacini and @vvasco .
Given that the default setting (when LANGUAGES is not specified) is to enable both CXX and C, and classically Find<package>.cmake scripts have been written under those assumptions, I think it is a good idea to add C to the project LANGUAGES argument .

Related bug: robotology/yarp#548 .

Prefer GenerateExportHeader to EXPORT_ALL_SYMBOLS

In my experience, having finer control over exported symbols is much better than exporting all of them (either via the default behavior of GCC-and-friends or via WINDOWS_EXPORT_ALL_SYMBOLS). Among these benefits:

  • smaller binary size (internal template instantiation names can be hidden)
  • better inlining; if the compiler/LTO knows a symbol isn't exposed at all, it can be more aggressively inlined)
  • less chance of someone using a symbol you didn't intend to expose (more a problem in C than C++)

Instead, GenerateExportHeader should be used to generate a header with _EXPORT macros to decorate classes, functions, and variables as being available to other libraries.

Missing `BUILD/INSTALL_${TARGET}_INCLUDEDIR` in CMakeLists.txt

Some variable are missing before invoking install_basic_package_files() in the main CMakeLists.txt (line #70).

In particular, just before line #70, a

get_property(${PROJECT_NAME}_TARGETS GLOBAL PROPERTY ${PROJECT_NAME}_TARGETS)

is missing to properly use the associated global variable.

Furthermore, for install_basic_package_files() to work properly, the following 2 variables need to be declared:

BUILD_${PROJECT_NAME}_INCLUDEDIR
INSTALL_${PROJECT_NAME}_INCLUDEDIR

I have an implementation that seems to work fine, even though it is not a clean solution in the case a user uses EXTRA_PATH_VARS_SUFFIX.

We should briefly discuss a solution when we have some time :-)

Typo in RPATH CMake function

I think here there's a typo:

add_install_rpath_support(BIN_DIRS "${CMAKE_INSTALL_FULL_LIBDIR}"
LIB_DIRS "${CMAKE_INSTALL_FULL_BINDIR}"
INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}"
USE_LINK_PATH)

It should be:

add_install_rpath_support(BIN_DIRS "${CMAKE_INSTALL_FULL_BINDIR}"
                          LIB_DIRS "${CMAKE_INSTALL_FULL_LIBDIR}"
                          INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}"
                          USE_LINK_PATH)

cc @claudiofantacci @traversaro @drdanz

C++ example repo created

Hi everybody,
I have to write a self-contained library for the new algorithm for calibration of FT sensors, so to avoid
rewriting everytime the same structure I tried to set up a reference repo for a typical C++ library.

It is based on https://gitlab.robotology.eu/walkman/template-pkg that uses CMake/YCM, but with some additions (that would be out of scope for Walkman):

  • example of use of generated_export_header() cmake macro for correctly exposing symbols and build shared library easily also on Windows,
  • example of use of CTest and relative travis/appveyor scripts.

There are still a lot of things to polish/finish, but I guess it can still be a useful reference.

@francesco-romano @drdanz @arocchi feel free to suggest improvements, even for changes in the
name of the repo/macros/source code structure. Perhaps Francesco can you add your usual rpath stuff?

cc @lornat75

Create a matching alias library with namspace prefix

Recommended practice taken from Chapter 16.2 of C. Scott's Professional CMake

For all library do

# Any sort of real library (SHARED, STATIC, MODULE or possibly OBJECT)
add_library(myRealThings SHARED src1.cpp ...)
add_library(otherThings STATIC srcA.cpp ...)
# Aliases to the above with special names
add_library(BagOfBeans::myRealThings ALIAS myRealThings)
add_library(BagOfBeans::otherThings ALIAS otherThings)

And then always refer to the scoped alias that is interpreted by CMake as either an imported target or an alias of a library and raise an error otherwise.

# Pull in imported targets from an installed package.
# See details in Chapter 23: Finding Things
find_package(BagOfBeans REQUIRED)
# Define an executable that links to the imported library from the installed package
add_executable(eatLunch main.cpp ...)
target_link_libraries(eatLunch PRIVATE
    BagOfBeans::myRealThings
)

This also ease integrating the library as part of a bigger project with minimal code change as follows (in particular for target_link_libraries() calls):

# Add BagOfBeans directly to this project, making all of its targets directly available
add_subdirectory(BagOfBeans)
# Same definition of linking relationship still works
add_executable(eatLunch main.cpp ...)
target_link_libraries(eatLunch PRIVATE
    BagOfBeans::myRealThings
  )

Update README.md

As a follow up of #29, #30 and #31, we need to update โš’ the README.md file bringing in some shiny โœจ props and fancy embellishments ๐Ÿ†๐Ÿ˜Ž

Set default CMAKE_BUILD_TYPE

Otherwise, the default build type will be None, with no optimization enabled.
The related code in YARP is the following (from https://github.com/robotology/yarp/blob/9a395f6e41e01d8d350b6a4e5e2b2f6c6f913b74/cmake/YarpOptions.cmake#L69):

if(NOT CMAKE_CONFIGURATION_TYPES)
  if(NOT CMAKE_BUILD_TYPE)
    # Encourage user to specify build type.
    message(STATUS "Setting build type to 'Release' as none was specified.")
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "Release")
  endif()
endif()

Migrate Travis to test on modern Linux distributions?

I recently renovated the Travis script for some robotology repos :

To be honest, I mostly cargo-culted the Travis scripts from wb-toolbox and Dart, as discussed in robotology/robotology-superbuild#96 .

I wonder if it could make sense to migrate the Travis template provide in here to run on modern Linux distribution, as the default Trusty distribution shipped by Travis is now 4-years old and not officially supported by the robotology software.

Improve doxygen target

List of improvements.

  • cmake_format configuration style.
  • Change PATH with DIRECTORY. PATH is the legacy call for CMake 2.8 which we do not support.
  • Give room to doxygen + graphiz (which includes dot executable for generating dependency/inheritance graphs) installation in the README.txt.
  • Generate a Doxygen TAG file.

See #22.

Install header directory preserving the original hierarchy

The current version of the LibTemplateCmake CMakeLists.txt uses PUBLIC_HEADER to list and install the header of the library.
While this approach is clean and straightforward, the process does not preserve the header folder hierarchy and, instead, install all header files in the same directory.

A simple workaround is to delete PUBLIC_HEADER property and use a install(DIRECTORY /path/of/include/dir DESTINATION /install/path/of/include/dir).

Is this solution sufficiently clean and satisfactory for most of the situation?
While this solution works smoothly, it undermines how to (I quote):

Specify public header files in a FRAMEWORK shared library target.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.