Dear Richard, On 1/1/21 11:06 PM, Richard B. Kreckel wrote:
Maintaining a second build system /is/ an additional burden and requires good justification. If it helps people build CLN on common platforms, well, that seems to be a good enough justification! That /I/ neither use or care about these platforms is, then, clearly subordinate.
Portability is nice and important. However I prefer CMake for a different reason: dependency management. Consider tools/CMakeLists.txt: ``` add_executable(viewgar viewgar.cpp) target_link_libraries(viewgar ginac::ginac) ``` What happens here is similar to $CXX `pkg-config --cflags --libs ginac` viewgar.cpp I.e. there's no need to set includes/definitions like in Makefile.am: AM_CPPFLAGS = -I$(srcdir)/../ginac -DIN_GINAC ...` It's enough to specify dependencies of `ginac` target once, and `target_link_libraries(viewgar ginac::ginac)` applies them automatically. The dependencies of `ginac` target are (see ginac/CMakeLists.txt) ``` target_compile_definitions(ginac PUBLIC $<BUILD_INTERFACE:IN_GINAC> PRIVATE -DLIBEXECDIR="${LIBEXECDIR}/" HAVE_CONFIG_H ) target_link_libraries(ginac PUBLIC cln::cln ${LIBDL_LIBRARIES}) target_include_directories(ginac PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) ``` This is roughly equivalent to a) `CPPFLAGS += -DLIBEXECDIR=$(LIBEXECDIR) HAVE_CONFIG_H` when compiling (lib)ginac itself (but NOT targets which depend on it) b) `CPPFLAGS += -DIN_GINAC` when compiling both (lib)ginac _and_ targets which depend on it. But if `ginac` target is exported (i.e. installed) this definition should NOT be added c) `CPPFLAGS += -I$(srcdir) -I$(builddir) -I$(builddir)/..` for both libginac and targets which depend on it. However, if libginac is exported (installed) use `-I${CMAKE_INSTALL_INCLUDEDIR}` instead (usually something like `$(PREFIX)/include/ginac`). d) LIBS += -lcln when linking both libginac and targets which depend on it. This also sets proper rpath when linking with shared libraries. e) Also add PUBLIC and INTERFACE definitions/includes/libraries from cln::cln target. Thus when compiling libcln as a shared library `-lgmp` is added only to libcln itself, but not to libginac (and viewgar, tests, etc) And EXPORT installs this information along with the target (library) itself. So that `target_link_libraries(viewgar ginac::ginac)` works when libginac is installed (exported). There's no way to express such dependencies with autotools. libtool tracks dependencies between libraries, so it's enough to viewgar_LDADD = ../ginac/libginac.la However a) includes, definitions, etc have to be specified manually b) libtool does not distinguish between private and public dependencies (this is why Linux distros don't include .la files in -devel packages) On the other hand pkg-config handles both --libs and --cflags, but a) it's not designed to handle dependencies between **targets** b) using uninstalled packages is next to impossible c) one has to describe the dependencies twice: both in .pc file and Makefile.am (as a result .pc files often get out of sync) d) rpath should be handled manually too (unlike libtool) As a result reusing code is much easier with CMake. For instance, to build a program one can put the whole CLN source into a subdirectory (git submodule) and use the following CMakeLists.txt: ``` cmake_minimum_required(VERSION 3.10) project(pi) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/cln) add_executable(pi src/pi.cc) target_link_libraries(pi cln::cln) ``` This automatically builds CLN (and its dependencies) before building `pi`. No more cd cln && ./autogen.sh && ./configure && make && make install env PKG_CONFIG_PATH=/oh/let/me/guess g++ src/pi.cc `pkg-config --libs --cflags cln` Best regards, Alexey