Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[llvm][CMake] Check dependency cxx source compiles #68549

Merged
merged 2 commits into from
Oct 18, 2023

Conversation

ekilmer
Copy link
Contributor

@ekilmer ekilmer commented Oct 9, 2023

If a CMake project doesn't enable the C language, then the CMake FFI and Terminfo find modules will fail their checks for compilation and linking.

This commit allows projects to enable only C++ by first checking if a C compiler is set before testing C source compilation; if not, it checks whether C++ compilation succeeds.

Fixes #53950

If a CMake project doesn't enable the C language, then the CMake FFI and
Terminfo find modules will fail their checks for linking.

This commit allows projects to enable only C++ by checking if a C
compiler is set, and if it is not, it checks whether C++ compilation
succeeds.
@AdvenamTacet
Copy link
Member

AdvenamTacet commented Oct 12, 2023

Hey, LGTM % naming but let's wait for a review from someone who worked on those cmakes. @jackoalan @JDevlieghere as you implemented/reviewed D114327, could you review that PR?

Also, @lzaoral does it fix your issue from #53950?

@ekilmer did you test it only on git-main version of LLVM?
Edit: also, I think SRC variable name is not the best choice, as that name is used also in a different context. Could you change it to something more descriptive?

@lzaoral
Copy link
Contributor

lzaoral commented Oct 12, 2023

@ekilmer Thanks for the PR but in the meantime I've stopped contributing to projects that depend on LLVM so I won't test it.

Moreover, unless this change is also backported to LLVM 14, projects will still need to use some workaround for the original issue.

@JDevlieghere
Copy link
Member

Is there any reason to not use check_cxx_source_compiles unconditionally?

@ekilmer
Copy link
Contributor Author

ekilmer commented Oct 16, 2023

Is there any reason to not use check_cxx_source_compiles unconditionally?

LLVM has C API bindings, so it's possible that a user would only enable the C language. Unconditionally using check_cxx_source_compiles would fail due to a missing C++ compiler.

@JDevlieghere
Copy link
Member

LLVM has C API bindings, so it's possible that a user would only enable the C language. Unconditionally using check_cxx_source_compiles would fail due to a missing C++ compiler.

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?

@ekilmer
Copy link
Contributor Author

ekilmer commented Oct 17, 2023

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 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:

# 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)
With a sibling file `sum.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);
}

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, it wasn't clear to me that this was functionality was also triggered when including llvm from a downstream project. Thank you for clarifying that and even including an example. This shows that it's indeed necessary to check both check_c_source_compiles and check_cxx_source_compiles. LGTM!

@ekilmer
Copy link
Contributor Author

ekilmer commented Oct 18, 2023

@JDevlieghere Great! I don't have commit access, so would you (or someone else we can ping) be able to help me out with landing this?

Thank you for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cmake Build system in general and CMake in particular
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CMake] find_package(LLVM CONFIG) may fail when the project does not use C
5 participants