Git Product home page Git Product logo

cmake-snips's Introduction

Please fix your CMake builds

As a very active downstream packager for a Linux distro, I often encounter packages that make assumptions which don’t hold for all systems they run on, or build tools they use. For projects using CMake especially, I find that many show at least one of the issues below.

I compiled a list of issues in this document that come up regularly in CMake projects. For most of them, there are simple best practices that can be followed to keep a project portable.

On a personal note, my recommendation is to move to the Meson build system where possible. It has a more modern design with better documentation, and does a good job avoiding common pitfalls. In my experience Meson makes life easier for both upstream developers and downstream packagers.

Hardcoding the installation paths

This is not limited to CMake. Fortunately, it is rare.

The Filesystem Hierarchy Standard is a useful default but there are many reasonable points someone would want to install a project to a different path than /usr. The standard also has shortcomings leading some distributions like GoboLinux or NixOS to deviate from it.

Your project should allow changing the paths using something like GNUInstallDirs. You also should not forget to update path references in the installed files.

Creating custom install path options

This is more of a inconvenience but if you ask users to pass -DMY_PROJECT_INSTALL_PREFIX=foo, you should consider switching to GNUInstallDirs. The module offers configurable variables for all common installation directories people are familiar with. No need to reinvent the wheel.

Assuming CMAKE_INSTALL_<dir> is relative path

There is no guarantee that variables like CMAKE_INSTALL_LIBDIR or CMAKE_INSTALL_INCLUDEDIR are relative paths, or even located under CMAKE_INSTALL_PREFIX. In fact, the documentation explicitly mentions that they can be absolute several times.

If you need absolute paths, never concatenate CMAKE_INSTALL_<dir> to CMAKE_INSTALL_PREFIX manually. Use CMAKE_INSTALL_FULL_<dir> instead.

Concatenating paths when building pkg-config files

This is actually the same issue as the previous one but with a slight twist. The variables in pkg-config files are expected to contain interpolations (e.g. completiondir=${datadir}/bash-completion) so that projects can install files relative their own directories instead of the ones of the project whose variables they use (see https://www.bassi.io/articles/2018/03/15/pkg-config-and-paths/). This means you cannot just use the CMAKE_INSTALL_FULL_<dir> variables and need to construct the paths yourself.

For CMake ≥ 3.20, you can use the cmake_path function:

cmake_minimum_required(VERSION 3.20) # For cmake_path function

#

cmake_path(APPEND libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")

configure_file(
  "${PROJECT_SOURCE_DIR}/my-project.pc.in"
  "${PROJECT_BINARY_DIR}/my-project.pc"
  @ONLY)

Unfortunately, CMake < 3.20 does not provide a function for joining paths so you will need to add it yourself. I have created a module you can copy to your code base and use as follows:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeScripts")

include(JoinPaths)

#

join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")

configure_file(
  "${PROJECT_SOURCE_DIR}/my-project.pc.in"
  "${PROJECT_BINARY_DIR}/my-project.pc"
  @ONLY)

See also a real-life example of the fix in {fmt} library.

License

This text is licensed under CC BY 4.0.

The source code is dual-licensed under MIT and CC0 1.0.

cmake-snips's People

Contributors

adamlwgriffiths avatar delroth avatar jtojnar avatar valodim 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

Watchers

 avatar  avatar  avatar  avatar

cmake-snips's Issues

Windows support for join_path

I wrote a bit about it at nih-at/libzip#213 (comment)

Windows absolute paths start with a drive letter. If IS_ABSOLUTE correctly detect them (CMake docs are not very detailed on it), these should work, otherwise it behaves just like before.

Second, there are also root-relative paths, those would need to be properly joined by a string manipulation: leave the old drive letter but replace the rest of the path. If CMake’s IS_ABSOLUTE correctly detects them as relative this will work incorrectly like before. If CMake incorrectly detects root-relative paths as absolute, it will produce incorrect path. (I would expect CMake to work correctly but some Windows user would have to check or inspect the CMake source code.)

Last, there are relative paths and these should work correctly as before (unless CMake detects them as absolute too.)

Using forward slash for directory separators should be fine for most cases. It would be nice to use proper platform-specific ones but this is not a regression.

So in our use case it works for Windows as before (barring a CMake bug), even though I would not expect Windows users to use pkg-config.

Since a merge request adding path manipulations functions have been merged to CMake this month and the fact that it should work in our use case I do not see a point in implementing proper Windows support.

Update README to include info about `cmake_path`?

Hi. Someone just reported an issue with our oss project .pc generation and pointed to your solution. Researching a little on the issue, I saw that you mentioned the new cmake_path command here. That would be an alternative to your own cmake module, right? Would you be willing to update your readme to show how to properly use that alternative?

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.