Skip to content

Instantly share code, notes, and snippets.

@shundhammer
Last active April 4, 2021 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shundhammer/12b6343309544a5920f51cd0063eeecf to your computer and use it in GitHub Desktop.
Save shundhammer/12b6343309544a5920f51cd0063eeecf to your computer and use it in GitHub Desktop.
New libyui CMake Build System and "make doc"

The new libyui CMake Build System and "make doc"

Building doxygen Autodocs

CMake supports generating doxygen-based autodocs pretty much out of the box; it's little more than

find_package( Doxygen REQUIRED dot )
doxygen_add_docs( doc ../src )

This creates a new make target doc that is not built by default, i.e. only upon make doc. This builds it by default:

doxygen_add_docs( doc ../src ALL )

In this case, it always builds it, i.e. it always runs doxygen.

Installing doxygen Autodocs

By default, CMake does not install doxygen autodocs at all. This has to be done manually.

One approach is to create a custom make target like install-doc:

add_custom_target( install-doc
  DEPENDS doc

  COMMAND mkdir   -m 755 -p ${DOC_INSTALL_DIR}/html
  COMMAND install -m 644 ${DOC_FILES} ${DOC_INSTALL_DIR}
  COMMAND cp -r ${CMAKE_CURRENT_BINARY_DIR}/html ${DOC_INSTALL_DIR}

  COMMENT "Installing documentation to ${DOC_INSTALL_DIR}" )

Another approach is to rely on make install and on the fact that we are not building docs by default, i.e. only when you invoke CMake with the BUILD_DOC=on option:

mkdir build
cd build
cmake -DBUILD_DOC=on ..

In that case, it is possible to add an install statement for the autodocs. Then each make install will also install the autodocs. But that only works well if the autodocs are always built.

doxygen_add_docs( doc ../src ALL )
install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${DOC_INSTALL_DIR} )

On the downside, that means that now building everything else should be explicitly disabled e.g. when building the -doc subpackage because now there is no more explicit install-doc target; it's just plain make install which will normally build everything else (the lib in src/, the examples in examples/, ...):

mkdir build
cd build
cmake -DBUILD_DOC=on -DBUILD_SRC=off -DBUILD_EXAMPLES=off -DBUILD_PKGCONFIG=off -DLEGACY_BUILDTOOLS=off ..

This now needs to go into the .spec file of the -doc subpackage, and when there is a new subdirectory with a new build target, this should be updated.

Chosen Approach

For the sake of keeping it simple, we use the explicit make doc and make install-doc approach; otherwise we would just be moving complexity around from doc/CMakeLists.txt to package/*-doc.spec where it is least expected (and thus less likely to be properly maintained).

Full doc/CMakeLists.txt

This uses a custom make install-doc, and make doc (i.e. doxygen) needs to be explicitly invoked when desired:

# CMakeLists.txt for libyui/doc

include( ../VERSION.cmake )

find_package( Doxygen REQUIRED dot )


set( PKG_NAME           libyui${SONAME_MAJOR} )
set( DOC_INSTALL_DIR    ${DOC_DESTDIR}/usr/share/doc/packages/${PKG_NAME} )


#
# Doxygen-generated autodocs
#

if ( DOXYGEN_FOUND )

  set( DOXYGEN_GENERATE_TREEVIEW yes ) # Enable views tree HTML frame
  set( DOXYGEN_QUIET             yes ) # Less verbose output
  set( DOXYGEN_WARN_LOGFILE      doxygen-warnings.log )
  # See build/CMakeDoxyfile.in for more supported variables

  doxygen_add_docs( doc ../src )

else()
  message( WARNING "Missing doxygen package" )
endif()


#
# Other (manually written) docs
#

file( GLOB DOC_FILES *.md ) # Collect all *.md files by wildcard
# Don't glob *.txt (CMakeLists.txt!)
# The license files (../COPYING*) are handled in the .spec file



# Define a new custom make target "install-doc".
# Notice that we can't use DESTDIR here since CMake only sets that
# for "make install", not for this custom "make install-doc".

add_custom_target( install-doc
  DEPENDS doc

  COMMAND mkdir   -m 755 -p ${DOC_INSTALL_DIR}/html
  COMMAND install -m 644 ${DOC_FILES} ${DOC_INSTALL_DIR}
  COMMAND cp -r ${CMAKE_CURRENT_BINARY_DIR}/html ${DOC_INSTALL_DIR}

  COMMENT "Installing documentation to ${DOC_INSTALL_DIR}" )

Alternative doc/CMakeLists.txt

This automatically always invokes make doc, and the autodocs are installed implicitly with make install:

# CMakeLists.txt for libyui/doc

include( ../VERSION.cmake )

find_package( Doxygen REQUIRED dot )


set( PKG_NAME           libyui${SONAME_MAJOR} )
set( DOC_INSTALL_DIR    /usr/share/doc/packages/${PKG_NAME} )


#
# Doxygen-generated autodocs
#

if ( DOXYGEN_FOUND )

  set( DOXYGEN_GENERATE_TREEVIEW yes ) # Enable views tree HTML frame
  set( DOXYGEN_QUIET             yes ) # Less verbose output
  set( DOXYGEN_WARN_LOGFILE      doxygen-warnings.log )
  # See build/CMakeDoxyfile.in for more supported variables

  doxygen_add_docs( doc ../src ALL )
  install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
    DESTINATION ${DOC_INSTALL_DIR} )

else()
  message( WARNING "Missing doxygen package" )
endif()


#
# Other (manually written) docs
#

file( GLOB DOC_FILES *.md ) # Collect all *.md files by wildcard
# Don't glob *.txt (CMakeLists.txt!)
# The license files (../COPYING*) are handled in the .spec file

install( FILES ${DOC_FILES} DESTINATION ${DOC_INSTALL_DIR} )

DESTDIR vs. DOC_DESTDIR

In the context of RPM / OBS builds, we need to support installing to $RPM_BUILD_ROOT. For make install, CMake supports this with the $DESTDIR environment variable which it makes available as the $DESTDIR CMake variable; it also automatically uses that as a prefix in common CMake install(...) calls.

For custom targets like make install-doc, it proved to be impossible to set or use that $DESTDIR variable; it's just always empty. It is only set when make install is called, not for any other make targets.

So, we had to introduce a separate $DOC_DESTDIR variable which is set via a CMake option:

cmake -DBUILD_DOC=on -DDOC_DESTDIR=$RPM_BUILD_ROOT ..
make install-doc
@anaselli
Copy link

anaselli commented Apr 4, 2021

I'd prefer the make DESTDIR=$RPM_BUILD_ROOT install way also because we use a single spec file for lib and docs

@shundhammer
Copy link
Author

shundhammer commented Apr 4, 2021

Actually, that was only a workaround since we still had the -doc subpackages; but we are in the process of dropping them.

From the CMake side, it is not expected to install those doxygen-generated autodocs. Generating it is well-supported and easy, but for installing them to /usr/share/doc/packages/libyui* I had to come up with a kludge: Basically a recursive copy of that html/ subdirectory to /usr/share/doc/packages/libyui* in a custom make target make install-doc. That's not pretty, and our plan is to get rid of that once the -doc packages are dropped.

Of course you can still generate the autodocs, but we plan to go with the CMake standards: Just leave them where they were generated so a developer can read them from there.

Also, please note that using DESTDIR does not work here (I tried!); it's only set during make install, not for custom targets such as our new make install-doc.

@shundhammer
Copy link
Author

So, unless you really want it for your own purposes, I recommend you don't care about that make install-doc packages; this will save a few lines in the .cmake file and some headaches. ;-)

We came to the conclusion that those -doc packages that only contained generated autodocs are really worthless; they just multiply the number of packages to handle. Anybody who develops with the library can easily generate the autodocs on the fly if needed. They add some nice formatting to the docs in the headers, and the only real benefit are hyperlinks to the parent class. But that's it.

@anaselli
Copy link

anaselli commented Apr 4, 2021

We don't have a doc package, we ship html file into libyui-devel, that's why make install is ok. DESTDIR works too, and the only thing to change is an option to pass to cmake to enable documents. I was changing doc/CMakeLists.txt to go to that direction, but when i realized you discarded that choice i gave up.
With the changing i made I can install all everywhere and works by using LD_LIBRARY_PATH in test environment. DESTDIR works too, and the default built directory tree is the one i have with the right now one. What i don't like, but it was like that already, is the way of chenging doc and example directory as said we don't have package after %{CMAKE_INSTALL_DATAROOTDIR}/doc. So since it looks similar to previous solution i think i can leave it as is.
Another thing we have in fedora and mageia too is %cmake macro for rpmbuild, that calls cmake with CMAKE_INSTALL_PREFIX and all changed accordingly to distro settings, that cannot work cause of issue 9, even if prefix is hard coded as /usr though.

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