Problem overview
I'm using CMake to build a project which contains a library based on MPI. The lib has to be built as both shared and static. When I build the project on my Fedora 20 system, everything goes without problem. When I build it on a Mac OS X El Capitan system, the building process fails with an error of the type:
ld: symbol(s) not found for architecture x86_64
Additional remarks
I cannot activate the option forcing automatic compilation of libs as both shared and static because this specific library is the only one that needs to be built as both.
Forcing the replacement of the C++ compiler command by the MPI wrapper (mpicxx) results in a successful build but completely breaks CLion's code analysis.
Minimal (non)working example
File: MPILib.h
#include <mpi.h>
void MPILib();
File: MPILib.c
#include "MPILib.h"
void MPILib() { MPI_Init(NULL, NULL); }
File: CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
enable_language(CXX)
set(CMAKE_MACOSX_RPATH 0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
find_package(MPI REQUIRED)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
add_library(mpilib_shared SHARED MPILib.cpp MPILib.h)
add_library(mpilib_static STATIC MPILib.cpp MPILib.h)
Build commands:
cmake .
make mpilib_static (succeeds)
make mpilib_shared (fails)
Related
I have the following error during cargo build of a project using cxx with cmake for compiling a C++ library to be callable in rust.
Here is the error from cargo build:
ld: warning: object file (/usr/local/lib/libwhisper.a(ggml.c.o)) was built for newer macOS version (12.6) than being linked (12.0)
ld: warning: object file (/usr/local/lib/libwhisper.a(whisper.cpp.o)) was built for newer macOS version (12.6) than being linked (12.0)
Undefined symbols for architecture x86_64:
"_cxxbridge1$whisper_init", referenced from:
whisper_rust::interop::ffi::whisper_init::hbcdc3c0c1120a6a9 in whisper_rust-2cf5d7323dfcdb42.1p80ceksqm40omuj.rcgu.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
This is my code in interop.rs using cxx::bridge macro:
#[cxx::bridge]
pub mod ffi {
unsafe extern "C++" {
type whisper_token;
type whisper_context;
fn whisper_init(path_model: &CxxString) -> *mut whisper_context; // this line causes the error
}
}
the last function declaration is the faulty one, commenting out the line make me build the project successfully but without interacting with the static C++ library this is useless.
That refers to a function decl. in the header:
struct whisper_context * whisper_init(const char * path_model);
Here's my build.rs:
println!("cargo:rerun-if-changed=src/whisper-cpp/*");
let dst = cmake::build("src/whisper-cpp");
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static=whisper");
And this is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.0)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
project(whisper VERSION 0.1.0)
# add compiler flags
set(CMAKE_CC_FLAGS "${CMAKE_CC_FLAGS} -I. -O3 -pthread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I. -O3 -std=c++11 -pthread")
# platform-dependent compiler flags
...
# add source files
aux_source_directory(. SRC_LIST)
# add library
add_library(${PROJECT_NAME} STATIC ${SRC_LIST})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "whisper.h")
# install
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include)
I'm not sure where my problem lies, I guess this is related the compilation step of CMakeLists but can be also generated by a bad build.rs setup.
I've already tried without success:
rebuilding / clean cache and then rebuilt
including the header file in interop.rs
looking for answers here, google, reddit, etc. for hours
changing the version of OSX required by cmake (this still doesn't make any difference shown in the error, makes me wonder...)
I spent way too hours doing this, I'm still learning FFI and I'll be very thankful if you can help me get out of this mess. Thank you.
EDIT: I updated the system, reinstalled cmake and set file in place of include in build.rs, this fixed the problem.
cxx will generate cpp code for your interop.rs in target/cxxbridge but it seems that you didn't include it in your CMakeLists.txt.
For example,
set(CXXBRIDGE ${CMAKE_CURRENT_SOURCE_DIR}/target/cxxbridge)
add_library(whisper SHARED your_cpp_file.cc ${CXXBRIDGE}/your_project_name/src/bridge.rs.cc)
I am developing a C++ library, including OpenCV, which will be used in a cross-platform Xamarin solution through a wrapper and the NuGet packaging system (see this guide). I configured a CMakeLists.txt file but I simply cannot get OpenCV to be correctly linked for both static (iOS) and dynamic (Android) libraries.
I tried to change the OpenCV_DIR variable, install and build OpenCV from sources and manually include the content of the OpenCV_INCLUDE_DIRS variable but nothing worked. I also noticed that the linking works when only using cv::Point. But the linking does not work when using cv::Mat, which I do not understand the reason.
The following is the CMakeLists.txt that I am using :
cmake_minimum_required (VERSION 3.2)
project (MyLib C CXX)
enable_testing()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
MESSAGE(STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS})
# Source and headers files
set(SOURCES File1.cpp File2.cpp)
set(HEADERS File1.h File2.h)
# Library
if(BUILD_SHARED_LIBS)
add_library (MyLib SHARED ${SOURCES} ${HEADERS})
target_compile_definitions(MyLib PUBLIC IS_BUILDING_SHARED)
else()
add_library (MyLib STATIC ${SOURCES} ${HEADERS})
endif()
# Dependencies
set(OpenCV_DIR /usr/local/Cellar/opencv/4.5.0_1/lib/cmake/opencv4)
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV_INCLUDE_DIRS = ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS = ${OpenCV_LIBS}")
message(STATUS "OpenCV_DIR = ${OpenCV_DIR}")
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(MyLib ${OpenCV_LIBS})
The following shows the location of OpenCV's files that are used during the build process. Everything seems alright.
-- OpenCV_INCLUDE_DIRS = /usr/local/Cellar/opencv/4.5.0_1/include/opencv4
-- OpenCV_LIBS = opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_alphamat;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn_objdetect;opencv_dnn_superres;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hfs;opencv_img_hash;opencv_intensity_transform;opencv_line_descriptor;opencv_mcc;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_quality;opencv_rapid;opencv_reg;opencv_rgbd;opencv_saliency;opencv_sfm;opencv_shape;opencv_stereo;opencv_structured_light;opencv_superres;opencv_surface_matching;opencv_text;opencv_tracking;opencv_videostab;opencv_viz;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto
-- OpenCV_DIR = /usr/local/Cellar/opencv/4.5.0_1/lib/cmake/opencv4
Android
The following is the commands that I am using to build the Android dynamic library (.so). I have installed the NDK and am building for each ABI (x86, x86_64, armeabi-v7a, arm64-v8a).
cmake ../.. -DCMAKE_TOOLCHAIN_FILE=/Users/$USER/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=21 -DANDROID_ABI=$abi_name -DBUILD_SHARED_LIBS=ON
cmake --build . --config Release
I directly get an error when building the library which is the following.
ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_gapi.4.5.0.dylib: unknown file type
ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_stitching.4.5.0.dylib: unknown file type
[...]
ld: error: /usr/local/Cellar/opencv/4.5.0_1/lib/libopencv_rapid.4.5.0.dylib: unknown file type
ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
iOS
The following is the commands that I am using to build the iOS static library (.a). I am using leetal's ​cmake toolchain file from this repository.
cmake ../.. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../../ios.toolchain.cmake -DPLATFORM=OS64COMBINED -DBUILD_SHARED_LIBS=OFF
cmake --build . --config Release
The compilation of the static library seems to work because no error message is printed. However, when the library is used in the final Xamarin solution, the linked library cannot be found and the following error is shown.
Native linking failed, undefined symbol: cv::Mat::deallocate(). Please verify that all the necessary frameworks have been referenced and native libraries are properly linked in. (MT5210)
Question
What am I missing in order to properly compile and link OpenCV into my C++ library ?
I am working on macOS Big Sur and uses the following tools versions:
cmake : 3.20.0-rc5
ndk : 23.0.7196353
apple clang : 12.0.0
I hope that the description of my problem is clear enough and I thank you in advance for any help.
We had same problems, including Xamarin's DllNotFoundException with message from last comment, which led me to this topic. What fixed the exception for us in the end was linking statically to OpenCV *.a libs instead of linking to the shared libopencv_java4.so file. So we now have a huge 30MB nativelib.so file for each android ABI in build output, instead of a pair of small nativelib.so and libopencv_java4.so per ABI. CMakeLists looks like this:
set( OpenCV_DIR "~/opencv/build/OpenCV-android-sdk/sdk/native/jni" )
find_package( OpenCV REQUIRED )
target_link_libraries( # Specifies the target library.
nativelib
${OpenCV_LIBS})
Another thing in our project is we use OpenCV optional modules and had to create a custom OpenCV build, which I guess ensures our native library and OpenCV are compiled against same NDK version. I suppose using the prebuilt OpenCV distribution and compiling against a different NDK version could lead to problems too otherwise.
I'm totally confused and in need of help from someone who has created C++ shared library that will work on any platform using any IDE.
What i have done so far:
1) Created a shared library using cmake in Ubuntu.
2) Transferred source files and Makefile (cmake) to MacOSX (El Capitan)
3) Created the build directory
4) Using Terminal in Mac OS, i ran :
$ cmake ..
$ sudo make install
5) Created an Xcode iOS Project that support armv7 and arm64 architectures
6) Used header search path and library search path to find the headers and library i had installed in
/usr/local/include/
and
/usr/local/lib
7) Used one of the included one of the library header file in main.mm (renamed main.m) and created an object for the class
8) Build the project gives me error because of following reason
ld: warning: ignoring file /usr/local/lib/libMyLibrary.dylib, file was built for x86_64 which is not the architecture being linked (arm64): /usr/local/lib/libMyLibrary.dylib
Here are the contents of my cmake
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lsqlite3")
#Adding source files
file(GLOB SOURCES "src/*.cpp")
#Generate the shared library from the sources
add_library(MyLibraryName SHARED ${SOURCES})
target_compile_options(MyLibraryFolder PRIVATE -std=c++11 -lsqlite3)
add_executable(MyLibraryName ${SOURCES})
target_link_libraries(MyLibraryName PRIVATE -lsqlite3)
#Set the location for library installation. Use "sudo make install" to apply
install(TARGETS MyLibraryName DESTINATION /usr/local/lib)
install(DIRECTORY inc/${MyLibraryName_CPP} DESTINATION /usr/local/include)
Can anyone help me with this, Please...
In your step 4, you're compiling the library on MacOS, which is x86_64; you can NOT just copy it to iOS's project, because iOS uses arm64.
So you should cross-compile the library for arm64 and use it for your iOS project.
I'm trying to use glbinding in my own project. I'm using cmake to build everything. The problem is linker cannot find this library. Probably I don't build library thus it cannot be linked, but I don't know how to achive that.
I've written linking code according to https://github.com/hpicgs/glbinding#linking-binaries.
Cmake:
set(SOURCE_FILES main.cpp)
add_executable(AKOpenGLEngine ${SOURCE_FILES})
set(CMAKE_PREFIX_PATH ${CMAKE_MODULE_PATH} glbinding )
find_package(glbinding REQUIRED)
include_directories(${GLBINDING_INCLUDES})
target_link_libraries(AKOpenGLEngine glbinding ${GLBINDING_LIBRARIES})
Error:
Linking CXX executable AKOpenGLEngine
ld: library not found for -lglbinding
main.cpp:
#include <glbinding/gl/gl.h>
int main(void) {
glbinding::Binding::initialize();
exit(EXIT_SUCCESS);
}
My current project structure:
Have you tried to remove the glbinding from target_link_libraries? ${GLBINDING_LIBRARIES} should be sufficient; it passes <your_specific_file_path_to_glbinding_library> to the linker. With -lglbinding the linker searches for a library within some default directories, your glbinding or build directory not included, thus throwing a library not found. To verify the content of ${GLBINDING_LIBRARIES} you can print it to cmake output, e.g., via message(STATUS ${GLBINDING_LIBRARIES}). However, i also suggest to integrate glbinding as external project as suggested by #janisz.
EDIT: sorry, didn't see the valid, but collapsed answer of #jet47
I downloaded libboost1.50-all in Raspberry Pi and has successfully compiled and execute a program using threads. Libraries were also found in CMake. I then copied the libraries of the boost and its include from /usr/lib and /usr/include/boost respectively to C:\Boost such that the hierarchy becomes:
C:
-> Boost
-> lib
... files
-> include
-> boost
... files
I then used the same CMakeLists.txt and the source code but the library was not found.
NOTE: The cross compiler that I used is fully working and I was able to produce an executable with CMake in Cygwin using the std library. I even specified the location of the library and the user and the root.
Is there anything that I missed out?
cmake_minimum_required(VERSION 2.8)
set(BOOST_ROOT C:/Boost/)
set(BOOST_INCLUDEDIR C:/Boost/include/)
set(BOOST_LIBRARYDIR C:/Boost/lib/)
SET(Boost_DEBUG ON)
find_package(Boost 1.50.0 COMPONENTS thread system)
if (Boost_FOUND)
include_directories (${Boost_INCLUDE_DIRS})
add_executable (thread thread.cpp)
target_link_libraries(thread ${Boost_LIBRARIES})
endif()
Use CMAKE -GUI and then check whether your boost libraries are detected . If not then manually set in the CMAKE-GUI and configure again.
TEMPORARY SOLUTION that I was able to come up to!
I placed the boost lib and include to where the cross compiler is installed since the cross compile was able to link the source code to libstdc++.
The library is placed here:
C:\cygwin\opt\cross\x-tools\arm-unknown-linux-gnueabi\arm-unknown-linux-gnueabi\sysroot\lib
The include files are placed here:
C:\cygwin\opt\cross\x-tools\arm-unknown-linux-gnueabi\arm-unknown-linux-gnueabi\include\c++\4.6.3
The CMakeLists content is as follows now:
cmake_minimum_required(VERSION 2.8)
add_executable (thread main.cpp)
target_link_libraries(thread boost_thread boost_system)
Open Cygwin terminal and invoke cmake there, then make. Viola! It now compiles successfully! :>
The magic lies in here:
target_link_libraries(thread boost_thread boost_system)
I found this in one of the questions here in Stackoverflow where someone said to manually link the libraries..
Even though that it worked, why is it that CMake cannot detect the boost library both in Windows (Cygwin terminal) and Linux (VMware) -- These I tried -- but the library was found in Raspberry Pi (Raspbian) using the same CMakeLists.txt and main.cpp. Isn't it the purpose of CMake is to find the libraries itself? If I were just to link them manually, better do it like this then:
arm-unknown-linux-gnueabi-g++.exe -lboost_thread -lboost_system