[llvm] [llvm][CMake] Check dependency cxx source compiles (PR #68549)

Eric Kilmer via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 16 17:49:15 PDT 2023


ekilmer wrote:

> These modules are used when configuring the LLVM build itself. Can you really do that with just a C compiler? I'm aware of the bindings but without a C++ compiler, you can't build the thing it's binding in the first place. So is there a configuration mode where you only build the C bindings against a pre-built LLVM? Is libffi or terminfo used in those C bindings?

You're correct that building the LLVM project requires a C++ compiler, and I'm not sure if building the C bindings separately is possible, but it doesn't look like it. I'm also not sure if libffi or terminfo are used in the C bindings.

However, I think that is beside the point. This PR is fixing _downstream consumers_ of LLVM---those building projects out-of-tree.

In the linked issue #53950, the opening post gives a small, standalone CMakeLists.txt that calls `find_package(LLVM)`. The way [LLVM's installed configuration file](https://github.com/llvm/llvm-project/blob/39f4ec5854a1ca34c70343c3ed1648a6be5b6b82/llvm/cmake/modules/LLVMConfig.cmake.in#L51-L66) is written, it _always_ tries to find libffi and terminfo (when LLVM itself was configured and built to find and use them).

A user might want to (or already does) _only_ enable the C compiler, and I think we should continue to support that. Unless the LLVM C bindings were to be split from the other targets (a breaking change), a call to `find_package(LLVM)` will always (unless it was built without) attempt to run the tests when finding libFFI and Terminfo.

More concretely, the following is an example project that currently works using LLVM 17, 16, 15, and 14 C bindings, and unconditionally using `check_cxx_source_compiles` would break it:

```cmake
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(llvm-c-test LANGUAGES C)

find_package(LLVM REQUIRED)

include_directories(${LLVM_INCLUDE_DIR})
add_executable(sum sum.c)
target_link_libraries(sum PRIVATE LLVM-C)
```

<details>
  <summary>With a sibling file `sum.c`</summary>

  ```c
/**
 * Copied from https://github.com/QDucasse/LLVM-C/blob/9cfdece261d406f6dcdf90aa42843843707a7a43/examples/Chapter1/sum.c
 * 
 * LLVM equivalent of:
 *
 * int sum(int a, int b) {
 *     return a + b;
 * }
 */

#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/BitWriter.h>
#include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h>

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
    // Module creation
    LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");

    // Function prototype creation
    LLVMTypeRef param_types[] = { LLVMInt32Type(), LLVMInt32Type() };
    LLVMTypeRef ret_type = LLVMFunctionType(LLVMInt32Type(), param_types, 2, 0);
    LLVMValueRef sum = LLVMAddFunction(mod, "sum", ret_type);
    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(sum, "entry");
    // Builder creation
    LLVMBuilderRef builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, entry);

    // Instruction added to the builder
    LLVMValueRef tmp = LLVMBuildAdd(builder, LLVMGetParam(sum, 0), LLVMGetParam(sum, 1), "tmp");
    LLVMBuildRet(builder, tmp);

    //Analysis
    char *error = NULL;
    LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
    LLVMDisposeMessage(error);

    // Bitcode writing to file
    if (LLVMWriteBitcodeToFile(mod, "sum.bc") != 0) {
        fprintf(stderr, "error writing bitcode to file, skipping\n");
    }

    // Dispose the builder
    LLVMDisposeBuilder(builder);
}
  ```

</details>

https://github.com/llvm/llvm-project/pull/68549


More information about the llvm-commits mailing list