0

I am new to CMake and LLVM/Clang, so I installed LLVM with brew (brew install llvm and updated my PATH as suggested by homebrew export PATH="/usr/local/opt/llvm/bin:$PATH") for learning purposes and I tried a simple main.c in my macOS:

(Note: I researched for similar answers to this particular issue in 1, 2, 3, 4, 5, 6, 7 and 8 but answers so far were not useful for me)

main.c

#include <clang-c/CXString.h>
#include <stdio.h>

void show_clang_version(void) {
        CXString version = clang_getClangVersion();
        printf("%s\n", clang_getCString(version));
        clang_disposeString(version);
}

int main( int argc, const char *const * argv )
{
        show_clang_version();
        return 0;
}

And then a "simple" CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(cmake-libclang VERSION 0.1.0)


set(triple "x86-64")
set(CMAKE_C_COMPILER clang)
set(CMAKE_LINKER ld64.lld)


message(STATUS "C   compiler: ${CMAKE_C_COMPILER_ID}  version: ${CMAKE_C_COMPILER_VERSION}" )
message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER_ID} version: ${CMAKE_CXX_COMPILER_VERSION}" )

######################################################################
# LLVM Package
######################################################################

find_package(LLVM REQUIRED CONFIG)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Using LLVM prefix directory: ${LLVM_PREFIX_DIR}")
message(STATUS "Using LLVM include directory: ${LLVM_INCLUDE_DIRS}")
message(STATUS "Using LLVM link directories: ${LLVM_LIBRARY_DIRS}")
message(STATUS "Using LLVM link directory: ${LLVM_LIBRARY_DIR}")
message(STATUS "Using LLVM binary directory: ${LLVM_BINARY_DIR}")
message(STATUS "Using LLVM definitions: ${LLVM_DEFINITIONS}")
message(STATUS "Using LLVM search paths: ${LLVM_SEARCH_PATHS}")

include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})

######################################################################
# CLANG package
######################################################################
find_package(CLANG CONFIG REQUIRED)
set(CLANG_LIBRARY_DIR ${LLVM_INCLUDE_DIRS})
set(CLANG_LIBRARY_DIRS ${CLANG_LIBRARY_DIR})

message(STATUS "Using ClangConfig.cmake in: ${CLANG_CMAKE_DIR}")
message(STATUS "Using CLANG include directory: ${CLANG_INCLUDE_DIRS}")
message(STATUS "Using CLANG link directory: ${CLANG_LIBRARY_DIR}")
message(STATUS "Using CLANG link directory: ${CLANG_LIBRARY_DIRS}")
message(STATUS "Using CLANG built-in directory: ${CLANG_BUILTIN_DIR}")
message(STATUS "Using CLANG_LIBRARY_DIRSNG definitions: ${CLANG_DEFINITIONS}")
message(STATUS "Using CLANG lib: ${CLANG_CLANG_LIB}")
message(STATUS "Using CLANG libs: ${LIBCLANG_LIBRARY}")

include_directories(${CLANG_INCLUDE_DIRS})
link_directories(${CLANG_LIBRARY_DIR})
add_definitions(${CLANG_DEFINITIONS})

######################################################################
# Parameters
######################################################################

add_executable(cmake-libclang main.c)

# Find the libraries that correspond to the LLVM components
# that we wish to use and link against LLVM libraries
llvm_map_components_to_libnames(llvm_libs -13)
target_link_libraries(cmake-libclang ${llvm_libs})

So I build this way and everything seems ok:

$ cmake .
-- The C compiler identification is AppleClang 12.0.5.12050022
-- The CXX compiler identification is AppleClang 12.0.5.12050022
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- C   compiler: AppleClang  version: 12.0.5.12050022
-- C++ compiler: AppleClang version: 12.0.5.12050022
-- Found ZLIB: /Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib/libz.tbd (found version "1.2.11")
-- Found LibXml2: /Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/lib/libxml2.tbd (found version "2.9.4")
-- Found LLVM 13.0.1
-- Using LLVMConfig.cmake in: /usr/local/opt/llvm/lib/cmake/llvm
-- Using LLVM prefix directory:
-- Using LLVM include directory: /usr/local/opt/llvm/include
-- Using LLVM link directories: /usr/local/opt/llvm/lib
-- Using LLVM link directory: /usr/local/opt/llvm/lib
-- Using LLVM binary directory: /usr/local/opt/llvm
-- Using LLVM definitions: -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-- Using LLVM search paths:
-- Using ClangConfig.cmake in: /usr/local/opt/llvm/lib/cmake/clang
-- Using CLANG include directory: /usr/local/opt/llvm/include
-- Using CLANG link directory: /usr/local/opt/llvm/include
-- Using CLANG link directory: /usr/local/opt/llvm/include
-- Using CLANG built-in directory:
-- Using CLANG definitions:
-- Using CLANG lib:
-- Using CLANG libs:
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/veronica/test-project

Now here comes the weird part. The error is as follows:

cmake --build . --clean-first
[ 50%] Building C object CMakeFiles/cmake-libclang.dir/main.c.o
/Users/veronica/main.c:5:28: warning: implicit declaration of function 'clang_getClangVersion' is invalid in C99 [-Wimplicit-function-declaration]
        CXString version = clang_getClangVersion();
                           ^
/Users/veronica/main.c:5:18: error: initializing 'CXString' with an expression of incompatible type 'int'
        CXString version = clang_getClangVersion();
                 ^         ~~~~~~~~~~~~~~~~~~~~~~~
1 warning and 1 error generated.
make[2]: *** [CMakeFiles/cmake-libclang.dir/main.c.o] Error 1
make[1]: *** [CMakeFiles/cmake-libclang.dir/all] Error 2
make: *** [all] Error 2

I search the function:

grep clang_getClangVersion /usr/local/opt/llvm/include/clang-c/Index.h
CINDEX_LINKAGE CXString clang_getClangVersion(void);

So I include the Index.h in main.c

#include <clang-c/CXString.h>
#include <clang-c/Index.h>
...

But finally I get this error:

$ cmake --build .
[ 50%] Building C object CMakeFiles/cmake-libclang.dir/main.c.o
[100%] Linking C executable cmake-libclang
Undefined symbols for architecture x86_64:
  "_clang_disposeString", referenced from:
      _show_clang_version in main.c.o
  "_clang_getCString", referenced from:
      _show_clang_version in main.c.o
  "_clang_getClangVersion", referenced from:
      _show_clang_version in main.c.o
ld: symbol(s) not found for architecture x86_64
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [cmake-libclang] Error 1
make[1]: *** [CMakeFiles/cmake-libclang.dir/all] Error 2
make: *** [all] Error 2

This is my LLVM config:

$ llvm-config --version --prefix --includedir --libdir --libs
13.0.1
/usr/local/Cellar/llvm/13.0.1_1
/usr/local/Cellar/llvm/13.0.1_1/include
/usr/local/Cellar/llvm/13.0.1_1/lib
-lLLVM-13

I would love an explanation (or better suggestions on how to fix this) to what's happening here because all .dylib files under /usr/local/opt/llvm/lib/ says "Mach-O 64-bit dynamically linked shared library x86_64"

Any ideas are welcomed.

PS: Here is the verbose output using -v with cmake

[ 50%] Linking C executable cmake-libclang
/Users/veronica/vcpkg/downloads/tools/cmake-3.22.2-osx/cmake-3.22.2-macos-universal/CMake.app/Contents/bin/cmake -E cmake_link_script CMakeFiles/cmake-libclang.dir/link.txt --verbose=1
clang  -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk -mmacosx-version-min=11.6 -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/cmake-libclang.dir/main.c.o -o cmake-libclang   -L/usr/local/opt/llvm/lib  -L/usr/local/opt/llvm/include  -Wl,-rpath,/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/include -lLLVM-13
Undefined symbols for architecture x86_64:
  "_clang_disposeString", referenced from:
      _show_clang_version in main.c.o
  "_clang_getCString", referenced from:
      _show_clang_version in main.c.o
  "_clang_getClangVersion", referenced from:
      _show_clang_version in main.c.o
ld: symbol(s) not found for architecture x86_64
clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [cmake-libclang] Error 1
make[1]: *** [CMakeFiles/cmake-libclang.dir/all] Error 2
make: *** [all] Error 2
Veronica
  • 280
  • 2
  • 12
  • Did you try to link against "libclang"? I'm no expert in CMake so I cannot say what to change. – the busybee Jun 23 '22 at 10:00
  • That's what `llvm_map_components_to_libnames(llvm_libs -13) target_link_libraries(cmake-libclang ${llvm_libs})` are supposed to do I guess. – Veronica Jun 23 '22 at 21:53
  • My fault, I didn't study the linker command in all depth, it seems to be there. Now you could check that this library includes the missing functions. GCC has "objdump" for this, unfortunately I don't know the equivalent command for Clang. – the busybee Jun 24 '22 at 06:10
  • For llvm most commands are llvm-{old-tool-name},so it would be llvm-objdump. Just found that CMake generates to use with system ld which is different from LLVM ld, even if I force to use CMAKE_LINKER to lld-link (the LLVM version of the linker)!!! Apparently doing `make` uses the /bin/ld from a OSX sysroot SDK??? I don't know how people can work with this. – Veronica Jun 24 '22 at 06:15
  • Querying the compiler's version -- something mostly only relevant at compile time -- via *run-time* code seems... confusing. Why would you want to do this in the first place? "Simple" looks diffferent. If you link to a *shared* library, you will also not get the version of your host machine, but of the *target* machine (which would need to have libclang installed to run your program). Weird. – DevSolar Jun 24 '22 at 23:12

0 Answers0