occa icon indicating copy to clipboard operation
occa copied to clipboard

undefined symbols when linking libocca.dylib with Metal

Open BenWibking opened this issue 1 year ago • 1 comments

When building with ./configure-cmake.sh on macOS 13.3:

[ 64%] Linking CXX shared library lib/libocca.dylib
ld: warning: directory not found for option '-F/Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk/System/Library/Frameworks/Metal.framework /Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk/System/Library/Frameworks/CoreServices.framework /Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk/System/Library/Frameworks'
Undefined symbols for architecture arm64:
  "_MTLCopyAllDevices", referenced from:
      occa::api::metal::getDeviceCount() in metal.mm.o
      occa::api::metal::getDevice(int) in metal.mm.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [lib/libocca.dylib] Error 1
make[1]: *** [CMakeFiles/libocca.dir/all] Error 2
make: *** [all] Error 2

BenWibking avatar Mar 28 '23 22:03 BenWibking

@BenWibking Adding -framework Metal -framework Cocoa to the linker flags is needed on macOS. The following build script works for me (i use llvm from brew in order to get OpenMP support):

#!/bin/bash

cmake -DCMAKE_C_COMPILER="clang"\
      -DCMAKE_CXX_COMPILER="clang++"\
      -DCMAKE_EXE_LINKER_FLAGS="-framework Metal -framework Cocoa"\
      -DCMAKE_SHARED_LINKER_FLAGS="-framework Metal -framework Cocoa"\
      -DENABLE_EXAMPLES=ON\
       . -B build > ./build.log 2>&1
cd build ; make -j4 >> ../build.log 2>&1 ; cd ..

atillack avatar Sep 19 '23 21:09 atillack

I ran into this problem as well. It seems that the link line for libocc.dylib is missing some frameworks. It looks like this on my machine:

/usr/bin/g++ ... -Xlinker -framework -Xlinker OpenCL -Xlinker -framework -Xlinker AppKit

If I change the way linking is done in FindMETAL.cmake like so:

diff --git a/cmake/FindMETAL.cmake b/cmake/FindMETAL.cmake
index cfbdcfb3..e1251246 100644
--- a/cmake/FindMETAL.cmake
+++ b/cmake/FindMETAL.cmake
@@ -20,7 +20,5 @@ if(METAL_FOUND AND NOT TARGET OCCA::depends::METAL)
   # Create our wrapper imported target
   # Put it in the OCCA namespace to make it clear that we created it.
   add_library(OCCA::depends::METAL INTERFACE IMPORTED)
-  set_target_properties(OCCA::depends::METAL PROPERTIES
-    INTERFACE_LINK_LIBRARIES "${METAL_LIBRARY} ${CORE_SERVICES} ${APP_KIT}"
-  )
+  target_link_libraries(OCCA::depends::METAL INTERFACE ${METAL_LIBRARY} ${CORE_SERVICES} ${APP_KIT})
 endif()

The link line ends up being:

... -Xlinker -framework -Xlinker OpenCL -Xlinker -framework -Xlinker Metal -Xlinker \
-framework -Xlinker CoreServices -Xlinker -framework -Xlinker AppKit

notice that Metal and CoreServices are now included. Seems like cmake is not handling the linking correctly using the set_target_properties. My cmake version is 3.26.4.

andrsd avatar Mar 28 '24 17:03 andrsd