Thoughts on improving the cross-compiling documentation

I’ve successfully compiled igraph’s C core to Webassembly for one of my projects, which enables the creation of some cool web applications that use igraph in the browser. This was mostly - and surprisingly - painless; the only sticking point was that Section 4.3 was a little vague about the exact workflow for generating and using a different arith.h. At the very least, it would have been helpful to see the exact CMake command to define a custom arith.h path - I needed some trial and error to eventually get:

set(F2C_EXTERNAL_ARITH_HEADER "path/to/custom/arith.h" CACHE FILEPATH "" FORCE)

Listing a few case studies on how exactly to generate a cross-compiled arith.h would also have been nice. For example, this is the CMake file used to generate my Wasm-compatible arith.h.

Thanks for the feedback; we will improve the documentation a bit in the section that you mentioned. However, before doing that, I’d like to understand why you are setting things the way you do it.

In theory, the preferred way for cross-compiling igraph and setting the path to the arith.h header should be done in the invocation to CMake (that is, if you are building igraph on its own and not as part of another project):

$ mkdir build
$ cd build
$ cmake .. -DF2C_EXTERNAL_ARITH_HEADER=path/to/custom/arith.h
$ cmake --build .

An alternative way is to use the CMake GUI (if you have it installed):

$ mkdir build
$ cd build
$ ccmake .
# set things on the GUI, optionally making advanced variables
# visible by pressing 't'
$ cmake --build .

Now, I would have assumed that if igraph is built as part of another project, one can simply use set(F2C_EXTERNAL_ARITH_HEADER "path/to/custom/arith.h") in the parent CMakeLists.txt file, without the CACHE FILEPATH "" FORCE part. Can you explain why these arguments are necessary?

Also, there are multiple ways to include igraph as an external project into another if simply linking to igraph is not enough (as it is in your case). My approach was typically to vendor igraph’s source in the project tree, and then call something like add_subdirectory(vendor/igraph) in CMakeLists.txt. It could be the case that since you are using FetchContent, things work differently and that’s why the extra arguments to set() are necessary, but I’d like to understand this before documenting it. There is also the ExternalProject module in CMake, which apparently allows passing extra arguments to CMake in the configuration step of the sub-project, so this could be yet another place where F2C_EXTERNAL_ARITH_HEADER is injected.

Long story short, I’m primarily interested in whether the set() command you outlined above could be simplified by omitting the CACHE FILEPATH "" FORCE part or they are absolutely necessary in your use-case.

I am not at all familiar with compiling for WebAssembly. Is (static) linking really not possible with this system? Do you really need to compile igraph and your project at the same time? Is it not possible to first compile igraph into a static library, then link to it from your project?

Thanks both - responses below. I’ll preface this by saying that I’m definitely a CMake novice, so there may well be a smarter way of doing things than the approach I ended up with.

Indeed, that’s what I tried first. But apparently, CMake’s local variables (defined by SET() without CACHE) are not the same as CMake’s cache variables (defined by SET() with CACHE). So setting the former doesn’t actually get alter the variable used by igraph/vendor/f2c/CMakeLists.txt.

Further reading of various CMake docs indicates that the cache variables are very much designed with command line arguments in mind, and indeed, -DF2C_EXTERNAL_ARITH_HEADER=path/to/custom/arith.h works fine. However, sometimes it’s nice to just throw it into the CMakeLists.txt so that it’s included in every build, no matter what. As such, I followed the advice here (see comments about the “make-shift global variable”) to forcibly set it, always, to the desired path.

For those who are interested, I made a little example to demonstrate:

cmake_minimum_required(VERSION 3.14)

project(test
    VERSION 1.0.0
    DESCRIPTION "Testing"
    LANGUAGES CXX)

set(F2C_EXTERNAL_ARITH_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/arith.h")

include(FetchContent)

FetchContent_Declare(
    igraph
    URL https://github.com/igraph/igraph/releases/download/0.9.4/igraph-0.9.4.tar.gz
    URL_HASH MD5=ea8d7791579cfbc590060570e0597f6b
)

FetchContent_MakeAvailable(igraph)

When cross-compiled with Emscripten’s CMake configuration, this gives a warning about an unset F2C_etc., which is only eliminated when adding those extra flags to SET().

(An extra consideration is that I use the same CMakeLists.txt to generate the arith.h in the first place, by adding some instructions to cross-compile and execute the arithchk.c thing. In this case, it’s natural to set the F2C_etc. variable inside the CMakeLists.txt because CMake already knows the location of the newly generated arith.h. Setting it on the command line makes it a bit more awkward because I need to manually ensure that the path I generated inside the CMakeLists.txt is the same as that used on the command line.)

To be honest, I think the real issue here is that CMake’s way of setting cache variables inside CMakeLists.txt is way more complicated than setting it on the command line. Maybe this is by design, I don’t know, but it isn’t really an issue with igraph itself. Nonetheless, it would have been helpful if the igraph C installation docs provided a link to some instructions on setting these cache variables inside the CMakeLists.txt, given that the same documentation already shows how to set some of these variables in command-line cmake invocations.

Static linking is possible, but not for object files generated for the host architecture. I basically need to build libgraph.a as a Wasm “static library”, and then I link my project (also compiled to Wasm) to that. Which makes sense to me; the Wasm binary won’t have the full numerical capabilities of any given host architecture, given that the same binary needs to run on everyone’s browser.

So, I could certainly compile igraph somewhere else and re-use the resulting libgraph.a static library in all my igraph-related Wasm projects. But that initial compilation would still need to use a separate toolchain and a different arith.h that is appropriate to the Wasm target.