Skip to content

Instantly share code, notes, and snippets.

@shundhammer
Last active March 17, 2021 09:45
Show Gist options
  • Save shundhammer/2d2b9bcf4b62df5b139daeceec8283ab to your computer and use it in GitHub Desktop.
Save shundhammer/2d2b9bcf4b62df5b139daeceec8283ab to your computer and use it in GitHub Desktop.
New Libyui CMake Build System

The New (2021/01) CMake Build System for Libyui

Overview

  • Simple
  • No voodoo
  • Conforming to standard CMake docs
  • Self-sufficient; no external files needed
  • Enough in-line documentation to get started even with very little CMake know-how
  • No more half-dozen magic little .cmake files with bits and pieces of information
  • No central .cmake files that do magic things, are hard to read and understand, almost impossible to change because they are so convoluted, and completely out of date since CMake improved a lot over all those years.
  • No magic variables all over the .cmake files that are unclear what they are and where they are filled with content, yet needed in hand-written .cmake files.

Key Files

  • Toplevel CMakeLists.txt
  • Toplevel Makefile.repo as a starting point and reminder how things work
  • Toplevel VERSION.cmake (the only one of the little .cmake files that is left over)
  • src/CMakeLists.txt

Other (less important) Files

  • doc/CMakeLists.txt for doxygen-generated autodocs
  • examples/CMakeLists.txt in some subprojects

Details

Toplevel Makefile.repo

This is the starting point for most operations. It's only convenience; you can easily do all those operations completely manually. But with this file, you don't need to guess what to do and how to do it.

Normal usage:

make -f Makefile.repo
cd build
make
sudo make install

Or:

make -f Makefile.repo build
sudo make -C build install

Or (everything manually):

rm -rf build
mkdir build
cd build
cmake ..
make
sudo make install

https://github.com/libyui/libyui/blob/master/Makefile.repo

#
# Makefile.repo for libyui
#

# Local Variables:
#    mode: Makefile
# End:


all: clean configure build-hint

build-hint:
	@echo ""
	@echo "To build:"
	@echo ""
	@echo "  cd build"
	@echo "  make"
	@echo ""

configure:
	mkdir build; \
	cd build; \
	cmake ..

build: clean configure
	cd build; \
	make -j $$(nproc)

# This needs root privileges, of course
install: configure
	cd build; \
	make -j $$(nproc) && make install

clean:
	rm -rf build

package:
	rake package

doc:
	test -d build || mkdir build
	cd build; \
	cmake -DBUILD_DOC=on .. ; \
	make doc

install-doc: doc
	cd build; \
	make install-doc

version-bump:
	rake version:bump

# Just an alias
bump-version: version-bump


# Enforce rebuilding some targets unconditionally, even if a file or directory
# with that name exists; otherwise the timestamp of that file or directory
# would be checked.
#
# We need this because we have a subdirectory doc/, a subdirectory package/
# and possibly a subdirectory build/ here.
.PHONY: doc package build

Toplevel CMakeLists.txt

This file contains some options that can be set on the cmake command line, some global definitions, and it descends into subdirectories. There is not much magic here.

There is a separate command line option for each subdirectory to configure whether or not this subdirectory should be built. For example, to build without examples/, you would invoke cmake like this:

rm -rf build
mkdir build
cd build
cmake -DBUILD_EXAMPLES=off ..
make
sudo make install

https://github.com/libyui/libyui/blob/master/CMakeLists.txt

# CMakeLists.txt for libyui
#
# Usage:
#
#   mkdir build
#   cd build
#   cmake ..
#
#   make
#   sudo make install
#
# Restart with a clean build environment:
#   rm -rf build
#
# Show the complete compiler commands with all arguments:
#   make VERBOSE=1

cmake_minimum_required( VERSION 3.10 )
project( libyui )

# Options usage:
#
#   cmake -DBUILD_DOC=on -DBUILD_EXAMPLES=off ..

option( BUILD_SRC         "Build in src/ subdirectory"                on )
option( BUILD_EXAMPLES    "Build C++ -based libyui examples"          on  )
option( BUILD_DOC         "Build class documentation"                 off )
option( BUILD_PKGCONFIG   "Build pkg-config support files"            on  )
option( LEGACY_BUILDTOOLS "Install legacy cmake buildtools"           on  )
option( WERROR            "Treat all compiler warnings as errors"     on  )

# Non-boolean options
set( DOC_DESTDIR "" CACHE STRING "Destination directory prefix for installing docs" )

#----------------------------------------------------------------------


# As of now, no support for /usr/local instead of /usr. But CMake DESTDIR works.
set( CMAKE_INSTALL_PREFIX /usr )

set( CMAKE_INSTALL_MESSAGE LAZY ) # Suppress "up-to-date" messages during "make install"


# Initialize compiler flags for all targets in all subdirectories
add_compile_options( "-Wall" )
add_compile_options( "-Os" )    # Optimize for size (overrides CMake's -O3 in RELEASE builds)

if ( WERROR )
  add_compile_options( "-Werror" )
endif()


#
# Descend into subdirectories
#

# Build and install auxiliary files first so this doesn't scroll away any important messages

if ( LEGACY_BUILDTOOLS )
  add_subdirectory( legacy-buildtools )
endif()

if ( BUILD_PKGCONFIG )
  add_subdirectory( pkgconfig )
endif()

#----------------------------------------------------------------------

if ( BUILD_SRC )
  add_subdirectory( src )
endif()

if ( BUILD_EXAMPLES )
  add_subdirectory( examples )
endif()

if ( BUILD_DOC )
  # Notice that this is only built upon "make doc" and installed upon "make install-doc"
  add_subdirectory( doc )
endif()

src/CMakeLists.txt

This is where the actual build instructions for the source code is.

Unlike the previous build system, this is complete and self-contained; no hidden magic, no voodoo, no collecting tidbits of information from "magic places" like all those tiny .cmake files one directory level above (!). No more PROJECTINFO.cmake or SOURCELIST.cmake, no magic locating of libs and headers that we need here from some faraway place. Keep it simple is the (new) principle here.

https://github.com/libyui/libyui/blob/master/src/CMakeLists.txt

# CMakeLists.txt for libyui/src

include( ../VERSION.cmake )
include( GNUInstallDirs )       # set CMAKE_INSTALL_INCLUDEDIR, ..._LIBDIR

find_package( Boost REQUIRED )


set( TARGETLIB          libyui )
set( TARGETLIB_BASE     yui    )

set( HEADERS_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/yui )

# if DESTDIR is set, CMAKE_INSTALL_INCLUDEDIR already contains it
# during "make install" (but not for other make targets!):
#
#    sudo make install DESTDIR=/work/foo
#
# -> the include files are installed to /work/foo/usr/include/...
# We need that for RPM builds to install everything to $RPM_BUILD_ROOT.


set( SOURCES
  YUI.cc
  YApplication.cc
  YWidgetFactory.cc
  YOptionalWidgetFactory.cc
  ...
  ...
  )


set( HEADERS
  YUI.h
  YApplication.h
  YWidgetFactory.h
  YOptionalWidgetFactory.h
  ...
  ...
  )


# Add shared lib to be built
add_library( ${TARGETLIB} SHARED ${SOURCES} ${HEADERS} )


#
# Include directories and compile options
#

# Generate Libyui_config.h where some CMake variables are expanded
# for use in the C++ code. This file is NOT installed upon "make install".
configure_file( Libyui_config.h.in Libyui_config.h )
target_include_directories( ${TARGETLIB} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} )

# Add more compile options to this target in addition to those
# added in the toplevel CMakeLists.txt.
#
# Notice that CMake will automatically add -fPIC etc. where needed,
# like for this shared lib.
### target_compile_options( ${TARGETLIB} PUBLIC "-Dfoo" )

# Show the complete compiler commands with all arguments:
#   make VERBOSE=1

# Add more compile options to an individual source file:
### set_source_files_properties( YUI.cc PROPERTIES COMPILE_OPTIONS "-Dfoo" )


#
# Linking
#

# Libraries that are needed to build this shared lib
#
# We only use the parts of Boost that are completely contained in header files
# without any binary part, so we don't need to link against any Boost lib.
# Should that become necessary, add Boost::filesystem or whatever lib is
# needed. See also
# https://cliutils.gitlab.io/modern-cmake/chapters/packages/Boost.html
#
# If in doubt what is really needed, check with "ldd -u" which libs are unused.
target_link_libraries( ${TARGETLIB}
  dl
  pthread
  )


# https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#target-properties
set_target_properties( ${TARGETLIB} PROPERTIES
  VERSION       ${SONAME}           # From ../VERSION.cmake
  SOVERSION     ${SONAME_MAJOR}     # From ../VERSION.cmake
  OUTPUT_NAME   ${TARGETLIB_BASE}
  )


#
# Install
#

# Install the headers first so the message about the lib does not scroll away
install( FILES   ${HEADERS}   DESTINATION ${HEADERS_INSTALL_DIR} )
install( TARGETS ${TARGETLIB} LIBRARY )

Toplevel VERSION.cmake

This contains the package version and the SO (shared lib) version.

https://github.com/libyui/libyui/blob/master/VERSION.cmake

SET( VERSION_MAJOR "4")
SET( VERSION_MINOR "0" )
SET( VERSION_PATCH "0" )
SET( VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" )

SET( SONAME_MAJOR "15" )
SET( SONAME_MINOR "0" )
SET( SONAME_PATCH "0" )
SET( SONAME "${SONAME_MAJOR}.${SONAME_MINOR}.${SONAME_PATCH}" )

The Future

  • Merge all SUSE-maintained libyui Git repos into one (@mvidner is working on that)
  • Build each subpackage from one large tarball containing that complete merged repo
  • (Hopefully) keep package version numbers in sync (to be discussed)
  • (Hopefully) use one common VERSION.cmake file for all subpackages
  • Merge .changes files into a single one? (to be discussed)
  • Submit all subpackages at once to OBS (to be discussed)

Nice to Have

  • Get rid of the -doc subpackages; they only contain doxygen-generated autodocs of limited use. We will still be able to generate the autodocs (make docs), but only in-place, and they won't be installed.

    As a matter of fact, CMake has very good and easy-to-use support for generating autodocs, but no support at all to install them to the system; this seems to be a very clear indication that this is something very uncommon. It looks like we are only doing that for historical reasons.

    Whoever is working on a libyui-based application or on libyui itself will want to check out the sources anyway, and will want up-to-date autodocs for this very branch and version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment