CMakeLists.txt: Improving GiNaC/CLN (& ease of) integration?
Hiya, fine folks, 🤠 I'm trying to integrate GiNaC into my CMake-based project and I'm having some difficulty setting up the build. I was hoping you all could point me in the right direction. My questions: #1: How do you build GiNaC/CLN when working on your own projects? Am I the only one that uses CMake? #2: Could we make the CMake build system (and the integration of GiNaC) slightly easier to work with?
From a quick glance, CLN and GiNaC seem tightly interwoven. Am I correct in assuming there's a reason CLN doesn't have a CMakeLists.txt? Or is this mainly historical and can I safely start adding a CMake build?
-------------------------- # My problem: My general git/CMake/C++ workflow consists of integrating every dependency I have as a git submodule under a common directory and point my CMakeLists.txt at each dependency. This has worked for me so far and seems like a reasonably clean way of dealing with dependencies on platforms where they might not be immediately available (i.e. MINGW). GiNaC's CMake build searches via a module ('cmake/modules/FindCLN.cmake') for a fully built CLN. This is simply not possible during the configuration step of my CMake build since at that point, CLN isn't even fully configured yet! Anyone have any idea how best to integrate GiNaC and CLN? How do YOU do it? Are there any big projects using GiNaC that I can look at? # How do we improve the CMake building experience of GiNaC & CLN? I'm open to suggestions, but I think merely adding a CMakeLists.txt to CLN should enable a better GiNaC build experience without having to modify GiNaC itself! Maybe modify that module just a tad bit but that oughta do it. If so desired, CLN's CMake build could just be made a proxy for the autotools build. I've also noticed that CLN's autogen.sh downloads some things via HTTPS from some git repo. This could immediately be looked at during this process. # The task (I estimate) there's 1202 source files in CLN as of writing so this is quite a task. I even bumped into source files specific to HP/PA ("Hewlett Packard Precision Architecture") which preceded Itanium which itself will be Discontinued in 2021! This makes CLN quite the antique! None the worse for wear I guess. ;-) Unless I'm mistaken, I doubt anyone still uses HP/PA in production in this day and age. (Ahh, they don't make 'em like they used to...) All in all: Should I or anyone else start working on CLN's CMakeLists.txt? Kind Regards & Happy Holidays, Xunie
Hi,
I'm trying to integrate GiNaC into my CMake-based project and I'm having some difficulty setting up the build. ... can I safely start adding a CMake build?
It seems that using a CMake 'ExternalProject' would allow you to use CLN's configure-based build system from CMake [1]. No? It is usually a waste of time to maintain two build systems (for CLN, in this case) in parallel, when one is sufficient. Bruno [1] https://stackoverflow.com/questions/5971921/building-a-library-using-autotoo...
Hello! 28.12.2020, 07:03, "Bruno Haible" <bruno@clisp.org>: I propose to merge CMake build branch [1] into CLN [1] https://github.com/asheplyakov/cln/tree/cmake I've been using it to build CLN and GiNaC for a long time (since 2010 or so) both for Linux and Windows (MinGW).
It seems that using a CMake 'ExternalProject' would allow you to use CLN's configure-based build system from CMake [1]. No?
ExternalProject does *not* provide any integration. One has to manually define lots of preprocessor, compiler, linker flags both for ExternalProject itself and the code which uses it. With CMake all of these is a matter of target_link_library(myprogram PRIVATE cln::cln) This becomes very tedious if the program needs several external projects.
It is usually a waste of time to maintain two build systems (for CLN, in this case) in parallel, when one is sufficient.
I disagree. Firstly I don't think autotools based build is sufficient: a) Generating a correct configure script is rather nontrivial (sort of plug and pray) b) No integration with IDEs c) Building on Windows is a pain Secondly *maintaining* two build systems is not that bad. Especially when it's someone else (for instance me) who does the maintenance. Best regards, Alexey
Dear Alexei, On 28.12.20 07:40, Alexey Sheplyakov wrote:
Secondly *maintaining* two build systems is not that bad. Especially when it's someone else (for instance me) who does the maintenance.
(Unfortunately, we seem to be having a communication problem.) I recall that I tried your CMake patches for CLN twice and ran into some issues, see [1]. What is the status, now? All my best, -richy. [1] https://www.ginac.de/pipermail/ginac-devel/2020-August/002507.html -- Richard B. Kreckel <https://in.terlu.de/~kreckel/>
Happy New Year! 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. On the other hand, and as a matter of fact, I have little time to debug it. The existing Autotools-based build system isn't going to go away any time soon. It shouldn't be adversely affected by supporting CMake. Likewise, duplication must be kept at a minimum. The installed files should be the same. Etc. On 28.12.20 15:33, Alexey Sheplyakov wrote:
I've checked both type builds like this: autoreconf -i mkdir _build_autotools && cd _build_autotools && ../configure --disable-static && cd .. mkdir _build_cmake && cd _build_cmake && cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo .. && cd .. make -j4 -C _build_autotools & cmake --build _build_cmake & Both builds run concurrently and have completed just fine. Hence the question: could you please explain what exactly are you doing?
From https://github.com/asheplyakov/cln.git, I checked out the cmake branch. Then: $ ./configure && make distclean && ./configure && make It seems like cl_asm.S and cl_asm_GF2.S get deleted. (Also, would it not be best to rename the asm files included by cl_asm.S, too?) Or, then I tried $ ./configure && make $ cd .. && mkdir cln_build && cd cln_build && cmake -GNinja ../cln $ cmake --build . and ran into the same old problems: 1) None of the macros {char|short|int|long}_{little|big}_endian are defined in cln/intparam.h. 2) Redefinitions of makros in src/cl_config.h and cln/config.h, both files picked up by some source files. All my best, -richard. -- Richard B. Kreckel <https://in.terlu.de/~kreckel/>
Dear Alexey, On 03.01.21 08:59, Alexey Sheplyakov wrote:
Short answer: please run `make distclean` before starting CMake build.> I've added heuristcs (commit bb6e98ff6a611cc68068e4d84d49b9aa3761ef2a) so CMake tries to detect such a broken setup and gives a helpful advice.
This makes sense. Thanks!
(char endianness? what's that?)
:-) Unfortunately, one of your patches seems to have broken the expansion of @CL_VERSION@ in cln.pc with Autoconf build? Further, I noticed that Autoconf build defines long_long_*_endian, although it doesn't seem to be used at the moment. For consistency, could you add it, please? -richy. -- Richard B. Kreckel <https://in.terlu.de/~kreckel/>
Dear Richard, On 1/6/21 8:12 PM, Richard B. Kreckel wrote:
Unfortunately, one of your patches seems to have broken the expansion of @CL_VERSION@ in cln.pc with Autoconf build?
Fixed (commit a47b29e328b61242). While at it I've repaired `make dist` (commit 7ec104c8987a4603).
Further, I noticed that Autoconf build defines long_long_*_endian, although it doesn't seem to be used at the moment. For consistency, could you add it, please?
Done (commit 4556f49a15be9ff8). Best regards, Alexey
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
Hi Alexei, I've merged your patches for building with CMake. Sorry for the delay. -richy. -- Richard B. Kreckel <https://in.terlu.de/~kreckel/>
Hello, 28.12.2020, 03:33, Xunie <cln-list@ginac.de>:
I'm trying to integrate GiNaC into my CMake-based project and I'm having some difficulty setting up the build.
You could try https://github.com/asheplyakov/cln/tree/cmake In order to compile both CLN and GiNaC just put cln sources into ginac directory, and run CMake build. For instance git clone git://www.ginac.de/ginac.git cd ginac git clone -b cmake git://github.com/asheplyakov/cln.git mkdir _build cd _build cmake .. cmake --build . This will build both CLN and GiNaC Similarly one can include both GiNaC and CLN sources into another project, and basically add_subdirectory(ginac) Here is a complete example: https://www.ginac.de/git/?p=ginac.git;a=blob_plain;f=doc/examples/CMakeLists...
My questions: #1: How do you build GiNaC/CLN when working on your own projects? Am I the only one that uses CMake?
I use CMake to build both CLN and GiNaC
#2: Could we make the CMake build system (and the integration of GiNaC) slightly easier to work with? From a quick glance, CLN and GiNaC seem tightly interwoven. Am I correct in assuming there's a reason CLN doesn't have a CMakeLists.txt?
As far as I understand there's no technical reasons.
Or is this mainly historical and can I safely start adding a CMake build?
I think it's better to reuse the existing one. Best regards, Alexey
Hey Alexey. Thanks! Your suggestion of building CLN inside GiNaC's source directory. It seems to work fine. BUT I have some beef with it. 1) I hear that in-source building is not recommended with CMake. I'm not experienced enough with CMake to comment on this. So maybe I'm cargo-culting/parroting right now. I'll yield to your expertise if you say that building dependencies inside source directories is established/good CMake practice. But this seems like an old/outdated way of doing things with CMake. Anyone, please tell me if I'm right or wrong about that. I'll try and see if I can come up with a better solution. 2) The CMake code seems to be of a certain 'vintage' and doesn't play nice with merely using add_subdirectory( cln ) followed by add_subdirectory( ginac ). When doing this, there's a lot of CMake Policy CMP0002 errors. I set up test case demonstrating it here: https://github.com/Xunie/ginac-problem/ Try it yourself: # setup project git clone https://github.com/Xunie/ginac-problem.git cd ginac-problem git submodule init git submodule update cd .. # configure the build mkdir ginac-problem-build cd ginac-problem-build cmake ../ginac-problem When add_subdirectory( git-submodules/ginac ) is removed, the CMP0002 issues with *CLN* go away!??! Either I'm using CMake wrong or there's a problem with either GiNaC or CLN's CMake build that needs to be fixed. Which one is it? The following error repeated for different targets is what I get: CMake Error at git-submodules/cln/src/CMakeLists.txt:952 (add_library): add_library cannot create target "cln" because another target with the same name already exists. The existing target is a shared library created in source directory "/home/xunie/Desktop/tmp/PROJECT/git-submodules/cln/src". See documentation for policy CMP0002 for more details. I have no idea why CMP0002 is violated. How can add_library() name-clash with itself?! Short of setting CMP0002 policy to 'old' behavior, I have no fix yet. Is this even a problem with CLN and not GiNaC? I have no idea. On Monday, December 28, 2020 6:58 AM, Alexey Sheplyakov <asheplyakov@yandex.ru> wrote:
I think it's better to reuse the existing one. Oh definitely, I wasn't aware of your efforts because it wasn't in the official repo. (Another reason to integrate it?)
At the risk of stepping on toes; If that CMP0002 bug/feature is fixed, I see no reason to not integrate it into the official repo. But hey, it ain't my project and I'll leave it to you seasoned veterans to decide. :P Kind Regards, Xunie
participants (4)
-
Alexey Sheplyakov
-
Bruno Haible
-
Richard B. Kreckel
-
Xunie