# Developer notes

## `Cargo` vs `CMake`

Cargo/Rust and Cmake/C++ projects follows an almost opposite philosophy:
+ Cargo: dependency management is handled internally and the linking is mostly static (actually, it is more than that, it is bundled).
+ Cmake: dependency management is left to the environment and linking is mostly dynamic (no portable solution for bundled static libs).

Cargo promotes a static (bundled) linking model to manage the dependencies of a Rust project. Specifically, the default behavior for rust libraries, is to statically bundle all the dependencies inside of the resulting `.rlib` file. At the cost of increasing the weights of the intermediate artifacts (a rather small price to pay given the cost of storage nowadays), cargo solves a lots of link-time and run-time burdens with this approach. All the dependencies of a project are pulled and built automatically, and it is rarely needed to tweak `LD_LIBRARY_PATH` to run an application. Also, resulting binaries are portable.

Cmake promotes a dynamic linking model, in which shared object pre-built binaries are distributed via distribution package managers, and dependencies are resolved at run-time thanks to a dynamic linker. Some recent features of cmake partially help, but there is no real dependency management, no support for building bundled static libraries (static libraries containing all dependencies), and so on.

As of now, it seems essentially impossible to reliably build an artifact for all the versions of the concrete compiler that can be statically linked into a rust library. For this reason, the concrete compiler artifacts coming from the Cmake world can only be shared objects dynamically linked to rust libraries (with all the book-keeping it brings at run-time to ensure all dependencies are available).

## `ConcreteSys` and `concrete-sys`

`concrete-sys` is a thin binding providing the _compilation_ features of concrete. Ideally, following the cargo philosophy, it should be up to cargo to pull the concrete sources and build the necessary artifacts to be linked with `concrete-sys`. In practice, this is not doable given how long it takes to build `llvm`.

For this reason we pre-build, with CMake, a target specifically for the `concrete-sys` crate, which will then be pulled from the `github` repository at build-time. This Cmake library target is referred to as `ConcreteSys` (CamelCase) and is defined in the workspace level `CMakeLists.txt` file.

In order for `concrete-sys` (the rust crate) to bind against `ConcreteSys` (the cmake library target), we need to define an interface which can be compiled on the CMake/C++ side, and used on the cargo/rust side. This interface is defined in three file:
+ `concrete-sys/lib.h` and `concrete-sys/lib.rs` which kind of mirror each others for the cpp and the rust side of the interface.
+ `concrete-sys/lib.cpp` which contains the sources of the interface, and are compiled by cmake to the `ConcreteSys` target.

In practice, other files automatically generated by `CXX` (the rust-cpp binding tool we use), need to be included when compiling the interface. Those are automatically generated with the `cxx-bridge` command by CMake.

Assuming the `libConcreteSys.so` artifact is built, we rely on the `concrete-sys/build.rs` to bring it to the `target` folder (either from a local build directory, or from the distributed binaries).

## Non-transitive link-args for `concrete-sys` users.

`concrete-sys` is built as an `rlib`, and contains a dynamic link dependency on `libConcreteSys.so` file.

On macos, this means that for the crates depending on `concrete-sys`, they will contain a dependency to `@rpath/libConcreteSys.dylib`. The `@rpath` is a variable that can be set by the linker to help the dynamic linker locate the proper dynamic library. The dynamic linker will try the usual system-wide paths, and the different `@rpath` specified in the binary (`@rpath` can be a list of directory). Those can be set by adding link args such as `-Wl,-rpath,path_to_dylib`.

In our case, since the `libConcreteSys.so` is not distributed by system package-managers but by cargo which will pull it to the `target` dir, it will not be possible for the dynamic linker to find it in the usual system locations (`/usr/lib/`, `/usr/local/lib` etc). We have to set the `@rpath` properly when linking the final users of the `concrete-sys` crate, for the dynamic linker to find the shared object.

Unfortunately, `rustc-link-args` are not transitively propagated to dependent crates (See https://github.com/rust-lang/cargo/issues/9554). This means that emitting `-Wl,-rpath,path_to_dylib` from the `concrete-sys/build.rs` script won't set the `@rpath` in the user crates. The link arg must be provided when linking the final user of the `concrete-sys` crate.

In our case, `concrete-macro` is the main user of the `concrete-sys` crate. Since it contains procedural macros (which are under the hood compiled to `dylib`), we _must_ provide the proper link args when building it. This is achieved in two steps:
+ In the `concrete-sys/build.rs` script, the `libConcreteSys.dylib` artifact is pulled to the root of the target dir (either `target/debug` or `target/release`).
+ In the `concrete-macro/build.rs` script, link args setting the `@rpath` to the target root are issued.
