Huge amount of exports in .dll when linking some static libraries - cmake

I wrote some modules which use libraries from vcpkg. The problem is when i try to compile SHARED library, it exports all functions from those libraries, why is that? I can add, that when i try to compile .exe instead of .dll problem doesn't exist
I use MinGW GCC compiler
Main CMakeLists.txt:
cmake_minimum_required(VERSION 3.24)
project(RewrittenModule)
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-fno-ident -s -O3 -fno-ident -fno-use-linker-plugin -fdata-sections -ffunction-sections -fvisibility=hidden -fvisibility-inlines-hidden -fstack-protector -fuse-ld=lld -fno-math-errno -march=native -Wl,--gc-sections -Wl,--strip-all")
find_package(fmt CONFIG REQUIRED)
find_package(Protobuf CONFIG REQUIRED)
#import crypto and proto sub projects
add_subdirectory(utils)
add_subdirectory(crypto)
add_subdirectory(proto)
add_subdirectory(web)
add_subdirectory(windows_utils)
add_subdirectory(cmake_configs/windows_x64)
cmake_configs/windows_x64 CMakeLists.txt
add_library(Core SHARED ../../main.cpp ../../credentials.h)
set_target_properties(Core PROPERTIES PREFIX "")
set_target_properties(Core PROPERTIES OUTPUT_NAME "native")
target_link_libraries(Core PRIVATE utils)
target_link_libraries(Core PRIVATE fmt::fmt)
target_link_libraries(Core PRIVATE crypto)
target_link_libraries(Core PRIVATE proto)
target_link_libraries(Core PRIVATE web)
target_link_libraries(Core PRIVATE windows_utils)
Example module (proto) CMakeLists.txt
add_library(proto STATIC proto.cpp proto.h proto_messages/AuthResponse.pb.cc ....)
target_link_libraries(proto PRIVATE protobuf::libprotobuf)
target_link_libraries(proto PRIVATE crypto)
target_link_libraries(proto PRIVATE web)
List of exports is huge, it includes exports from OpenSSL Crypto, protobuf, curl..

After i added one exported function, it worked
extern "C"
__declspec(dllexport) void Test() {
}

Related

Link errors when using CMake and VCPKG with GoogleTest

As a bit of background, I have a project that I have been developing with Visual Studio and VCPKG manifest mode for some time, it contains one static library project and one unit test project. Everything has been working correctly. I'm now trying to migrate this solution to use CMake, this is my first time using CMake.
With CMake the VCPKG dependencies install correctly, and both the static library and unit tests compile, however it fails on the linking step with a large number of linker errors all related to the GoogleTest library. Here is the first, as an example:
CppSlippiTest.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl testing::internal::FormatMatcherDescription(bool,char const *,class std::vector<char const*,class std::allocator<char const *> > const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > const &)" (?FormatMatcherDescription#internal#testing##YA?AV$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##_NPEBDAEBV?$vector#PEBDV$allocator#PEBD#std###4#AEBV?$vector#V?$basic_string#DU?$char_traits#D#std##V$allocator#D#2##std##V?$allocator#V?$basic_string#DU$char_traits#D#std##V?$allocator#D#2##std###2##4##Z) referenced in function "private: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl cpp_slippi::MatchOptionalMatcherP2<class testing::internal::Eq2Matcher,class std::optional<unsigned char> >::gmock_Impl<class std::optional<unsigned char> const &>::FormatDescription(bool)const " (?FormatDescription#$gmock_Impl#AEBV?$optional#E#std###$MatchOptionalMatcherP2#VEq2Matcher#internal#testing##V?$optional#E#std###cpp_slippi##AEBA?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##_N#Z) [C:\Users\Derek\Projects\CppSlippi\build\Test.vcxproj]
There are 36 more of these.
Here is my CMakeLists.txt, slightly abridged for clarity:
cmake_minimum_required(VERSION 3.12...3.24)
# Must be before project()
set(VCPKG_TARGET_TRIPLET x64-windows-static)
project(CppSlippi
VERSION 1.0
DESCRIPTION "Slippi replay file parsing library for C++."
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(GTest CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
add_library(CppSlippi STATIC
CppSlippi/src/CppSlippi.cpp
CppSlippi/src/CppSlippi.h
...)
target_include_directories(CppSlippi PUBLIC CppSlippi/src)
target_compile_features(CppSlippi PUBLIC cxx_std_20)
target_compile_options(CppSlippi PUBLIC /MTd)
set_target_properties(CppSlippi PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(CppSlippi PUBLIC nlohmann_json::nlohmann_json)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)
include(GoogleTest)
endif()
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
add_executable(Test
Test/src/CppSlippiTest.cpp
...)
target_include_directories(Test PUBLIC Test/src)
target_compile_features(Test PUBLIC cxx_std_20)
target_compile_options(Test PRIVATE /bigobj /MTd)
set_target_properties(Test PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main)
gtest_discover_tests(Test)
endif()
Here is my VCPKG manifest:
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"name": "cpp-slippi",
"version": "1.0.0",
"description": "C++ Slippi replay parser.",
"builtin-baseline": "68b7fec22eb5fd9c0236b1e42b3c0deb8e771b37",
"dependencies": [
"gtest",
"nlohmann-json"
],
"supports": "windows"
}
And to build this I am running:
cmake --build build --target Test
I turned on --verbose to get more information, and this is the link command that CMake is running:
Link:
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\bin\HostX64\x64\link.exe /ERRORREPO
RT:QUEUE /OUT:"C:\Users\Derek\Projects\CppSlippi\build\Debug\Test.exe" /INCREMENTAL /ILK:"Test.dir\Debug\Test.ilk" /N
OLOGO /NATVIS:"C:\Users\Derek\Projects\CppSlippi\build\vcpkg_installed\x64-windows-static\share\nlohmann_json\nlohman
n_json.natvis" Debug\CppSlippi.lib "vcpkg_installed\x64-windows-static\debug\lib\manual-link\gtest_main.lib" "vcpkg_i
nstalled\x64-windows-static\debug\lib\gtest.lib" kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib
oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifes
t:embed /DEBUG /PDB:"C:/Users/Derek/Projects/CppSlippi/build/Debug/Test.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE
/NXCOMPAT /IMPLIB:"C:/Users/Derek/Projects/CppSlippi/build/Debug/Test.lib" /MACHINE:X64 /machine:x64 Test.dir\Debug
\CppSlippiTest.obj ...
Note the presence of gtest_main.lib and gtest.lib, these are the libraries that I believe should include the missing functions. I have checked that these files are present at the locations shown.
I know that in Visual Studio using the GoogleTest main requires adding an AdditionalDependency manually, but from all the instructions I can find this should not be necessary in CMake and the .lib is already in the command line. I did try using target_link_directories anyways, but this did not help.
At this point I am baffled and searching on Google and Stack Overflow has failed to turn up any help.
You link only one of 4 GoogleTest libraries to your app
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main)
Depending on the application needs, it should be linked to at least one more library
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gtest_main
GTest::gtest)
Or
target_link_libraries(Test PUBLIC
CppSlippi
nlohmann_json::nlohmann_json
GTest::gmock_main
GTest::gmock
GTest::gtest)

How CMake automatically detects header dependencies

I wonder how CMake automatically detects that main.cpp depends on header.h
// header.h
int f() {
return 0;
}
// main.cpp
#include "header.h"
int main() {
return f();
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(Cppref)
add_executable(main main.cpp)
When I run cmake . -B build it creates the following make target in ./build/CMakeFiles/main.dir/build.make
CMakeFiles/main.dir/main.cpp.o: CMakeFiles/main.dir/compiler_depend.ts
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/nikolay/Cpp/Train/Cppref/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object CMakeFiles/main.dir/main.cpp.o"
/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/nikolay/Cpp/Train/Cppref/main.cpp
Pay attention to the -MD compiler option, as
it is used to dump dependencies visible to the preprocessor.
So after the first build it will create ./build/CMakeFiles/main.dir/main.cpp.o.d with the following content
CMakeFiles/main.dir/main.cpp.o: /home/nikolay/Cpp/Train/Cppref/main.cpp \
/home/nikolay/Cpp/Train/Cppref/header.h
So whenever you change header.h, the target main.o will be rebuilt.

Why No ops registered when I try to load frozen model in Android NDK?

I want to use c++ tensorflow API through ndk and cmake, I can create the library but when I load a frozen model a lot of errors like this when I try to load graph:
E/native: op_kernel.cc:1148 OpKernel ('op: "PopulationCount"
device_type: "CPU" constraint { name: "T" allowed_values { list {
type: DT_INT32 } } }') for unknown op: PopulationCount
So I understand that my library does not support the operations.
Do I need to add another library to support these operations?
I based my Cmake script on this Cmakelist and
I used the build_android_all.sh script to build the dependencies for armeabi-v7a.
This is how my cmake script looks like:
cmake_minimum_required(VERSION 3.4.1)
include(ExternalProject)
SET(PROJECT_NAME tf_native_lib)
SET(OpenCV_FOUND true )
SET(PREBUILT_DIR ${TENSORFLOW_ROOT_DIR}/tensorflow/contrib/makefile/gen)
SET(TARGET_NSYNC_LIB ${TENSORFLOW_ROOT_DIR}/tensorflow/contrib/makefile /downloads/nsync/builds/${ANDROID_ABI}.android.c++11)
FIND_PACKAGE(OpenCV REQUIRED)
add_library( # Sets the name of the library.
${PROJECT_NAME}
SHARED
src/main/cpp/native-lib.h
src/main/cpp/native-lib.cpp
src/main/cpp/TensorflowInferenceHandler.h
src/main/cpp/TensorflowInferenceHandler.cpp
)
add_library(lib_proto STATIC IMPORTED )
set_target_properties(lib_proto PROPERTIES IMPORTED_LOCATION
${PREBUILT_DIR}/protobuf_android/${ANDROID_ABI}/lib/libprotobuf.a)
add_library(lib_nsync STATIC IMPORTED )
set_target_properties(lib_nsync PROPERTIES IMPORTED_LOCATION
${TARGET_NSYNC_LIB}/libnsync.a)
add_library(lib_tf STATIC IMPORTED )
set_target_properties(lib_tf PROPERTIES IMPORTED_LOCATION
${PREBUILT_DIR}/lib/android_${ANDROID_ABI}/libtensorflow-core.a)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIS_SLIM_BUILD \
-std=c++11 -fno-rtti -fno-exceptions \
-O2 -Wno-narrowing -fomit-frame-pointer \
-mfpu=neon -mfloat-abi=softfp -fPIE -fPIC \
-ftemplate-depth=900 \
-DGOOGLE_PROTOBUF_NO_RTTI \
-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} \
-Wl,--allow-multiple-definition \
-Wl,--whole-archive \
-fPIE -pie -v")
# MESSAGE("tensorflow lib dir ${TENSORFLOW_LIB_DIR}")
target_link_libraries( # Specifies the target library.
${PROJECT_NAME}
${OpenCV_LIBS}
android
dl
log
m
z
jnigraphics
lib_tf
lib_proto
lib_nsync)
include_directories(
${OPENCV_INCLUDE_DIRS}
${PREBUILT_DIR}/proto
${PREBUILT_DIR}/protobuf_android/${ANDROID_ABI}/include
${PREBUILT_DIR}/nsync/public
${TENSORFLOW_ROOT_DIR}/tensorflow/contrib/makefile/downloads/eigen
${TENSORFLOW_ROOT_DIR}/bazel-tensorflow/external/nsync/public
${TENSORFLOW_ROOT_DIR}/bazel-genfiles
${TENSORFLOW_ROOT_DIR}
../../../cpp_utils)
If this is not possible, where are the sources to link the tensorflow_inference.so with my Jni Sources?
Thanks in advance.
Unai.
The PopulationCount and few other Ops are declared in tensorflow/core/ops/bitwise_ops.cc. Add that file to the end of /tensorflow/contrib/makefile/tf_op_files.txt. Then recompile the Tensorflow. That is what worked for me.

including itensor library in my cmake project in clion

so I am very new to CLion and CMake, so sorry in advance for wrong usage of terminology. I am suffering the following problem:
In my project I want to include the ITensor library which is essentially a non-CMake project. I cloned the git to my computer and build the ITensor project. Next I wanted to use it in another project linking against it with CMake:
My Code in main.cpp:
#include <iostream>
#include "itensor.h"
int main() {
std::string some_string = "Hello world";
return 0;
}
and my CMakeLists.txt looks like:
cmake_minimum_required(VERSION 3.6)
project(tutorial)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(ITENSOR_DIR PATH/TO/ITENSOR)
include_directories(ITENSOR_DIR/itensor)
set(SOURCE_FILES
main.cpp
${ITENSOR_DIR}/itensor/itensor.h
${ITENSOR_DIR}/itensor/itensor.cc)
add_executable(tutorial ${SOURCE_FILES})
Unfortunately, the project 'tutorial' does not build in CLion. Likewise, CLion cannot resolve the dependency itensor.h.
Anybody an Idea for why this is, respectively how to fix it?
After trying Thomas5631's solution the compilation ran into linking issues with lapack. I solved this by adding some flags, though I'm not sure if all of them are required.
My CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(my_project)
#Bring the headers into the project (full or relative path)
include_directories(itensor)
#Link the Itensor library
add_library(itensor STATIC IMPORTED)
set_property(TARGET itensor PROPERTY IMPORTED_LOCATION /home/david/my_project/itensor/lib/libitensor.a)
#Set a variable with all the new flags
set(ITENSOR_FLAGS "-DPLATFORM_lapack -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0")
set(ITENSOR_LINK_FLAGS "-DPLATFORM_lapack -L/home/david/my_project/itensor/lib -litensor -lpthread -L/usr/lib -lblas -llapack")
#Append the new flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${ITENSOR_FLAGS}")
add_executable(my_project main.cpp)
target_link_libraries(my_project itensor "${ITENSOR_LINK_FLAGS}")
Motivation: In the folder itensor/project_template there is a sample program which is simple enough to compile with make (from the terminal). The output of the compilation reveals the flags:
g++ -m64 -std=c++11 -c -I. -I/home/david/my_project/itensor -I/usr/include -O3 -DNDEBUG -Wall -DPLATFORM_lapack -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0 -Wno-unused-variable -o myappname.o myappname.cc
[... some warnings ...]
g++ -m64 -std=c++11 -c -I. -I/home/david/my_project/itensor -I/usr/include -O3 -DNDEBUG -Wall -DPLATFORM_lapack -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0 -Wno-unused-variable -o myclass.o myclass.cc
g++ -m64 -std=c++11 -I. -I/home/david/my_project/itensor -I/usr/include -O3 -DNDEBUG -Wall -DPLATFORM_lapack -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0 -Wno-unused-variable myappname.o myclass.o -o myappname -L/home/david/my_project/itensor/lib -litensor -lpthread -L/usr/lib -lblas -llapack
I got around the issue with the following main.cpp:
#include <iostream>
#include "itensor/itensor.h"
int main() {
std::string some_string = "Hello world";
return 0;
}
And the following CMakeLists.txt:
project(tutorial)
cmake_minimum_required(VERSION 3.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#Bring the headers into the project
include_directories(/home/tom/Documents/workspace/ITensor/)
#Link the library
add_library(itensor STATIC IMPORTED)
set_property(TARGET itensor PROPERTY IMPORTED_LOCATION /home/tom/Documents/workspace/ITensor/lib/libitensor.a)
set(SOURCE_FILES main.cpp)
add_executable(tutorial ${SOURCE_FILES})
Where the path to ITensor can be either relative (using the ${PROJECT_SOURCE_DIR} variable) or absolute as I have shown.

Cmake test program cannot find -lgcc_s

I'm using cmake with custom GCC(with shared libraries) and during cmake compiler test I get following error:
The C compiler "/path/to/gcc/bin/gcc" is not able to compile a simple test program.
...
/path/to/gcc/x86_64-unknown-linux-gnu/bin/ld:
cannot find -lgcc_s
Here's a simple "testme.cpp" file:
#include <iostream>
int main( int argc, char * argv[] ) {
std::cout << "Hello world" << std::endl;
return 0;
}
and here's a CMakeLists.txt:
cmake_minimum_required(VERSION 2.6.2)
project(testme)
file( GLOB srcs "testme.cpp" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -std=c++11")
set(CMAKE_LDFLAGS "${CMAKE_LDFLAGS} -L/path/to/gcc/lib/gcc/x86_64-unknown-linux-gnu/lib64")
add_executable(testme ${srcs})
to build with my custom GCC I'm exporting CXX and CC:
export CXX=/path/to/gcc/bin/g++
export CC=/path/to/gcc/bin/gcc
and then hit:
cmake .
make
and the result is that it can't find libgcc_s.so which is located in the "lib/gcc/x86_64-unknown-linux-gnu/lib64" folder.
However, when I invoke gcc like this:
/path/to/gcc/bin/g++ testme.cpp -L/path/to/gcc/lib/gcc/x86_64-unknown-linux-gnu/lib64
it compiles successfully. I've tried to add it to LD_LIBRARY_PATH but that doesn't seem to help.
So, is there a way to pass library path to CMake compiler check?
Chrono Kitsune was sort of right ... /path/to/gcc/x86_64-unknown-linux-gnu/bin/ld was build with "--enable-shared" and libraries where not in systems search path.