Linking SDL2 with CMake [duplicate] - c++

This question already has an answer here:
LNK2019 - unresolved external symbol - C++ - SDL2 Library [duplicate]
(1 answer)
Closed 2 years ago.
I'm having problems linking SDL2 to my project, which probably are because I'm new to CMake, and I don't fully know how to create new projects with it. Every time and method I've tried to fix this problem has resulted in one of the following problems:
"Cannot locate WinMain#16"
Multiple undefined reference errors
undefined reference to `SDL_main`
I have attempted to use find_package, linking directly to files, linking to library files, following tutorials (for example https://trenki2.github.io/blog/2017/06/02/using-sdl2-with-cmake/), searching for answers (most of them talk about using find_package which I can't get to work) (for example Using SDL2 with CMake).
Project dependencies
SDL 2.0.12, CMake 3.17.0, 7-Zip, mingw32-make, wget
The project is supposed to be cross-platform, but the main devenv is Windows 10. All scripts are run from the root folder "vivaria".
Project structure
vivaria/
├── build/
│ └── [cmake build files]
├── buildtools/
│ └── SDL2/SDL2-2.0.12/lib/x86 (and x64)
│ ├── SDL2.lib
│ └── SDL2main.libs
├── deploy/
├── resources/
├── scripts/
│ ├── build_windows_debug_x86.bat
│ └── install_buildtools_windows.bat
└── src/
├── CMakeLists.txt
└── vivaria.cpp
build_windows_debug_x86.bat
cmake -G "MinGW Makefiles" -S .\src\ -B .\build\ -DCMAKE_BUILD_TYPE=Debug
cd .\build\
mingw32-make
vivaria.cpp
#include <iostream>
#include "SDL.h"
int main() {
if (SDL_Init(SDL_INIT_VIDEO) != 0){
std::cout << "Hello world" << std::endl;
return 1;
}
SDL_Quit();
return 0;
}
CMakeLists.txt: undefined reference to SDL_main
cmake_minimum_required(VERSION 3.17)
project(Vivaria VERSION 1.0.0)
set(CMAKE_CXX_GLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lmingw32")
# set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../buildtools")
set(SDL2_DIR "${INCLUDE_DIR}/SDL2/SDL2-2.0.12")
set(SDL2_INCLUDE_DIRS "${SDL2_DIR}/include")
set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/../deploy")
# Support both 32 and 64 bit builds
if (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
set(SDL2_LIBRARIES "${SDL2_DIR}/lib/x64/SDL2main.lib;${SDL2_DIR}/lib/x64/SDL2.lib")
else ()
set(SDL2_LIBRARIES "${SDL2_DIR}/lib/x86/SDL2main.lib;${SDL2_DIR}/lib/x86/SDL2.lib")
endif ()
# link dependencies
include_directories(${SDL2_INCLUDE_DIRS})
link_directories(${SDL2_LIBRARIES})
# Project files and linking
set(SOURCES vivaria.cpp)
add_executable(${PROJECT_NAME} vivaria.cpp)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})
Console output
F:\Koodit\Vivaria\build>mingw32-make
[ 50%] Linking CXX executable Vivaria.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: F:/Koodit/Vivaria/src/../buildtools/SDL2/SDL2-2.0.12/lib/x86/SDL2main.lib(Win32/Release/SDL_windows_main.obj):(.text[_main_getcmdline]+0xd1): undefined reference to `SDL_main'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\Vivaria.dir\build.make:104: recipe for target 'Vivaria.exe' failed
mingw32-make[2]: *** [Vivaria.exe] Error 1
CMakeFiles\Makefile2:91: recipe for target 'CMakeFiles/Vivaria.dir/all' failed
mingw32-make[1]: *** [CMakeFiles/Vivaria.dir/all] Error 2
Makefile:99: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
install_buildtools_windows.bat
set SDL2=SDL2-devel-2.0.12-VC.zip
set DOWNLOAD_DIR=%cd%\buildtools
set OUTPUT_DIR=%cd%\buildtools\SDL2
wget "https://libsdl.org/release/%SDL2%" -P "%DOWNLOAD_DIR%"
7z x "%DOWNLOAD_DIR%\%SDL2%" -y -o%OUTPUT_DIR%
del /F /Q %DOWNLOAD_DIR%\%SDL2%
As you can see I'm still "a bit" new to CMake, but I'm trying to learn.

Oof. Everything about your CMakeLists is wrong.
Never set CMAKE_CXX_FLAGS in your CMakeLists.txt
Never use include_directories or link_directories
Never use target_link_libraries without a visibility specifier.
Never set paths to libs manually.
Don't set your target names equal to the project name. It's pointless complexity and bad style.
This is all you need:
cmake_minimum_required(VERSION 3.16)
project(Vivaria VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(SDL2 REQUIRED)
add_executable(Vivaria vivaria.cpp)
target_link_libraries(Vivaria PRIVATE SDL2::SDL2)
Your code also has an error. You need to add this line to the top of your file
#define SDL_MAIN_HANDLED
First, use vcpkg to install SDL2. Then, with the above changes, this compiles and runs for me using the commands:
> mkdir build
> cd build
> cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=X:/path/to/vcpkg.cmake ..

Thanks to Tsyvarev!
Setting the macro SDL_MAIN_HANDLED in the source file fixed the problem.
#define SDL_MAIN_HANDLED // insert this
#include <iostream>
#include "SDL.h"
int main() {
if (SDL_Init(SDL_INIT_VIDEO) != 0){
std::cout << "Hello world" << std::endl;
return 1;
}
std::cout << "Hello world 2" << std::endl;
SDL_Quit();
return 0;
}

Related

How to properly link an installed library to the CMake in Windows?

I have a CMake project that uses mosquittopp. It is properly running on Linux without needing any additional configurations (i.e. #include <mosquittopp.h> works without target_include_directories; and libraries are linked without find_library)
However, when I try the same on Windows, I am constantly having undefined reference problems. Here is the minimal reproducible example:
Install mosquitto to the system; Here are some files from C:/Program Files/mosquitto:
├── libcrypto.dll
├── libssl.dll
├── mosquitto.dll
├── mosquitto.exe
├── mosquittopp.dll
├── devel
│   ├── mosquitto.h
│   ├── mosquitto.lib
│   ├── mosquittopp.h
│   └── mosquittopp.lib
Write and save the following to main.cpp:
#include <iostream>
#include <mosquittopp.h>
int main() {
std::cout << "hello world";
mosqpp::lib_init();
return 0;
}
Create the following CMakeLists.txt file:
111
cmake_minimum_required(VERSION 3.15)
project(sandbox LANGUAGES CXX)
add_executable(MainFile main.cpp)
target_include_directories(MainFile PUBLIC "C:/Program Files/mosquitto/devel")
target_link_libraries(MainFile "C:/Program Files/mosquitto/devel/mosquittopp.lib")
set_property(TARGET MainFile PROPERTY CXX_STANDARD 17)
set_property(TARGET MainFile PROPERTY CXX_STANDARD_REQUIRED On)
set_property(TARGET MainFile PROPERTY CXX_EXTENSIONS Off)
I tried to use different combinations of find_library(), absolute paths, adding and removing dll files, adding all lib files but to no avail.
EDIT: The error message in this example is:
[build] C:/Users/myuser/OneDrive/Desktop/test/main.cpp:6: undefined reference to `__imp__ZN6mosqpp8lib_initEv'
[build] collect2.exe: error: ld returned 1 exit status
[build] mingw32-make[2]: *** [CMakeFiles\MainFile.dir\build.make:101: MainFile.exe] Error 1
[build] mingw32-make[1]: *** [CMakeFiles\Makefile2:82: CMakeFiles/MainFile.dir/all] Error 2
[build] mingw32-make: *** [Makefile:90: all] Error 2
this is a minimal reproducible example, but the similar errors arise in the full project as well.
I think I know where the issue is now after looking at the error message and checking out mosquitopp.
My current guess is that you've downloaded pre-compiled binaries from their download page.
These binaries were built using MSVC (2019) however you are using mingw32 to build your project. This is apparent from the line here:
[build] mingw32-make[2]: *** [CMakeFiles\MainFile.dir\build.make:101: MainFile.exe] Error 1
You cannot use different compilers, the binaries will always most likely be different. So you have two options now to solve this:
Build your own mosquittopp library using mingw32
Build your application using MSVC 2019

How to include library from sibling directory in CMakeLists.txt for compilation

I am working on a C project as of recently and want to learn how to use CMake properly.
The project consists of the following directory structure (as of now):
.
└── system
├── collections
│ ├── bin
│ ├── build
│ ├── includes
│ └── src
└── private
└── corelib
├── bin
├── build
├── includes
└── src
Every directory including 'bin' sub-directories is a separate library. They contain a CMakeLists.txt each.
The plan is to link the libraries in such a way that, during development, no manual recompilation of 'corelib' should be required to receive updated code from it, while also ensuring that dependencies would be resolved once all libraries get compiled as SHARED libraries and put in a place such as 'usr/local/lib' or similar.
I have a dependency of library 'corelib' in library 'collections'.
Trying to resolve said dependency, I have come up with the following CMakeLists.txt in 'collections':
cmake_minimum_required(VERSION 3.0.0)
project(collections VERSION 0.1.0 LANGUAGES C)
set(LIBRARY_OUTPUT_PATH ../bin)
add_subdirectory(../private/corelib ${LIBRARY_OUTPUT_PATH})
include_directories(./includes)
aux_source_directory(./src SOURCES)
add_library(collections SHARED ${SOURCES} main.c)
However, this does not produce the result I am looking for, as I get the following output on build:
[main] Building folder: collections
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /home/codeuntu/Repositories/netcore-c/src/system/collections/build --config Debug --target all -j 6 --
[build] gmake[1]: *** No rule to make target '../bin/all', needed by 'all'. Stop.
[build] gmake[1]: *** Waiting for unfinished jobs....
[build] Consolidate compiler generated dependencies of target collections
[build] [ 50%] Built target collections
[build] gmake: *** [Makefile:91: all] Error 2
[build] Build finished with exit code 2
It seems this is the wrong way to go about it. Any help is greatly appreciated.
This is the CMakeLists.txt for 'corelib':
cmake_minimum_required(VERSION 3.0.0)
project(corelib VERSION 0.1.0 LANGUAGES C)
include_directories(./includes)
aux_source_directory(./src SOURCES)
set(LIBRARY_OUTPUT_PATH ../bin)
add_library(corelib SHARED ${SOURCES} main.c)
Binary directory has to be a subdirectory of current dir, it can't be above ../bin. Use:
add_subdirectory(../private/corelib some_unique_name)
Overall, let's fix some issues. A more advanced CMake might look like this:
# system/CmakeLists.txt
add_subdirectory(private EXCLUDE_FROM_ALL)
add_subdirectory(collections)
# system/collections/CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(collections VERSION 0.1.0 LANGUAGES C)
file(GLOB_RECURSE srcs *.c *.h)
add_library(collections ${srcs})
# Use only target_* intefaces
target_include_directories(collections PUBLIC
./includes
)
target_link_libraries(collections PRIVATE
corelib
)
# system/private/CMakeLists.txt
add_subdirectory(corelib)
# system/private/corelib/CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(corelib VERSION 0.1.0 LANGUAGES C)
file(GLOB_RECURSE srcs *.c *.h)
add_library(corelib ${srcs})
target_include_directorieS(corelib PUBLIC ./includes)
# system/CMakePresets.json
{
... see documentation ...
"configurePresets": [
{
...
"cacheVariables": {
"BUILD_SHARED_LIBS": "1",
"ARCHIVE_OUTPUT_DIRECTORY": "${binaryDir}/bin",
"LIBRARY_OUTPUT_DIRECTORY": "${binaryDir}/bin",
"RUNTIME_OUTPUT_DIRECTORY": "${binaryDir}/bin"
}
}
I.e. overall, I do not think every project inside system wants to compile his own separate instance of corelib, rather one corelib should be shared. Just add corelib once, from anywhere. Note that it doesn't have to be in order - you can target_link_libraries on targets before they are defined.

Unresolved external symbols with SDL2 and cmake [duplicate]

This question already has an answer here:
LNK2019 - unresolved external symbol - C++ - SDL2 Library [duplicate]
(1 answer)
Closed 2 years ago.
I'm having problems linking SDL2 to my project, which probably are because I'm new to CMake, and I don't fully know how to create new projects with it. Every time and method I've tried to fix this problem has resulted in one of the following problems:
"Cannot locate WinMain#16"
Multiple undefined reference errors
undefined reference to `SDL_main`
I have attempted to use find_package, linking directly to files, linking to library files, following tutorials (for example https://trenki2.github.io/blog/2017/06/02/using-sdl2-with-cmake/), searching for answers (most of them talk about using find_package which I can't get to work) (for example Using SDL2 with CMake).
Project dependencies
SDL 2.0.12, CMake 3.17.0, 7-Zip, mingw32-make, wget
The project is supposed to be cross-platform, but the main devenv is Windows 10. All scripts are run from the root folder "vivaria".
Project structure
vivaria/
├── build/
│ └── [cmake build files]
├── buildtools/
│ └── SDL2/SDL2-2.0.12/lib/x86 (and x64)
│ ├── SDL2.lib
│ └── SDL2main.libs
├── deploy/
├── resources/
├── scripts/
│ ├── build_windows_debug_x86.bat
│ └── install_buildtools_windows.bat
└── src/
├── CMakeLists.txt
└── vivaria.cpp
build_windows_debug_x86.bat
cmake -G "MinGW Makefiles" -S .\src\ -B .\build\ -DCMAKE_BUILD_TYPE=Debug
cd .\build\
mingw32-make
vivaria.cpp
#include <iostream>
#include "SDL.h"
int main() {
if (SDL_Init(SDL_INIT_VIDEO) != 0){
std::cout << "Hello world" << std::endl;
return 1;
}
SDL_Quit();
return 0;
}
CMakeLists.txt: undefined reference to SDL_main
cmake_minimum_required(VERSION 3.17)
project(Vivaria VERSION 1.0.0)
set(CMAKE_CXX_GLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lmingw32")
# set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
set(INCLUDE_DIR "${CMAKE_SOURCE_DIR}/../buildtools")
set(SDL2_DIR "${INCLUDE_DIR}/SDL2/SDL2-2.0.12")
set(SDL2_INCLUDE_DIRS "${SDL2_DIR}/include")
set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/../deploy")
# Support both 32 and 64 bit builds
if (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
set(SDL2_LIBRARIES "${SDL2_DIR}/lib/x64/SDL2main.lib;${SDL2_DIR}/lib/x64/SDL2.lib")
else ()
set(SDL2_LIBRARIES "${SDL2_DIR}/lib/x86/SDL2main.lib;${SDL2_DIR}/lib/x86/SDL2.lib")
endif ()
# link dependencies
include_directories(${SDL2_INCLUDE_DIRS})
link_directories(${SDL2_LIBRARIES})
# Project files and linking
set(SOURCES vivaria.cpp)
add_executable(${PROJECT_NAME} vivaria.cpp)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARIES})
Console output
F:\Koodit\Vivaria\build>mingw32-make
[ 50%] Linking CXX executable Vivaria.exe
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: F:/Koodit/Vivaria/src/../buildtools/SDL2/SDL2-2.0.12/lib/x86/SDL2main.lib(Win32/Release/SDL_windows_main.obj):(.text[_main_getcmdline]+0xd1): undefined reference to `SDL_main'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\Vivaria.dir\build.make:104: recipe for target 'Vivaria.exe' failed
mingw32-make[2]: *** [Vivaria.exe] Error 1
CMakeFiles\Makefile2:91: recipe for target 'CMakeFiles/Vivaria.dir/all' failed
mingw32-make[1]: *** [CMakeFiles/Vivaria.dir/all] Error 2
Makefile:99: recipe for target 'all' failed
mingw32-make: *** [all] Error 2
install_buildtools_windows.bat
set SDL2=SDL2-devel-2.0.12-VC.zip
set DOWNLOAD_DIR=%cd%\buildtools
set OUTPUT_DIR=%cd%\buildtools\SDL2
wget "https://libsdl.org/release/%SDL2%" -P "%DOWNLOAD_DIR%"
7z x "%DOWNLOAD_DIR%\%SDL2%" -y -o%OUTPUT_DIR%
del /F /Q %DOWNLOAD_DIR%\%SDL2%
As you can see I'm still "a bit" new to CMake, but I'm trying to learn.
Oof. Everything about your CMakeLists is wrong.
Never set CMAKE_CXX_FLAGS in your CMakeLists.txt
Never use include_directories or link_directories
Never use target_link_libraries without a visibility specifier.
Never set paths to libs manually.
Don't set your target names equal to the project name. It's pointless complexity and bad style.
This is all you need:
cmake_minimum_required(VERSION 3.16)
project(Vivaria VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(SDL2 REQUIRED)
add_executable(Vivaria vivaria.cpp)
target_link_libraries(Vivaria PRIVATE SDL2::SDL2)
Your code also has an error. You need to add this line to the top of your file
#define SDL_MAIN_HANDLED
First, use vcpkg to install SDL2. Then, with the above changes, this compiles and runs for me using the commands:
> mkdir build
> cd build
> cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=X:/path/to/vcpkg.cmake ..
Thanks to Tsyvarev!
Setting the macro SDL_MAIN_HANDLED in the source file fixed the problem.
#define SDL_MAIN_HANDLED // insert this
#include <iostream>
#include "SDL.h"
int main() {
if (SDL_Init(SDL_INIT_VIDEO) != 0){
std::cout << "Hello world" << std::endl;
return 1;
}
std::cout << "Hello world 2" << std::endl;
SDL_Quit();
return 0;
}

Compiling c++ project with 3rd party lib to WebAssembly

I have a simple c++ project which includes eigen. I'm able to compile the project on my own machine but having trouble to compile it to webassembly with emscripten.
Project structure:
.
├── CMakeLists.txt
├── include
│   └── HelloWasm
│   └── my_lib.h
└── src
├── main.cpp
└── my_lib.cpp
File contents:
CMakeLists.txt
cmake_minimum_required( VERSION 3.0 )
project( HelloWasm )
# flags
# include files
include_directories( ./include .include/HelloWasm ./src )
# target
add_executable( HelloWasm ./src/main.cpp ./src/my_lib.cpp )
# 3rd party libs
find_package(Eigen3 REQUIRED NO_MODULE)
include_directories(${EIGEN3_INCLUDE_DIR})
include/HelloWasm/my_lib.h
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using Eigen::MatrixXd;
class MyLib
{
private:
protected:
public:
MyLib()
{
}
~MyLib()
{
}
void eigen_test();
};
src/main.cpp
#include <iostream>
#include "HelloWasm/my_lib.h"
using namespace std;
int main()
{
MyLib my_lib;
my_lib.eigen_test();
}
src/my_lib.cpp
#include "HelloWasm/my_lib.h"
void MyLib::eigen_test()
{
MatrixXd m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1);
cout << '\n'
<< m << endl;
}
Compiling the project successfully locally:
mkdir build && cd build
cmake ..
make
➜ ./HelloWasm
3 -1
2.5 1.5
Errors when trying to compile to webassemply
(I tried following the steps provided in the emscripten docs)
mkdir build && cd build
cmake ..
emcmake cmake ..
output:
configure: cmake .. -DCMAKE_TOOLCHAIN_FILE=/Users/me/programming/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CROSSCOMPILING_EMULATOR="/Users/me/programming/emsdk/node/12.9.1_64bit/bin/node"
-- Configuring done
-- Generating done
CMake Warning:
Manually-specified variables were not used by the project:
CMAKE_TOOLCHAIN_FILE
-- Build files have been written to: /Users/me/programming/sandbox/cpp_sandbox/so_question_project/build
Now running make:
➜ emmake make
make: make
Scanning dependencies of target HelloWasm
[ 33%] Building CXX object CMakeFiles/HelloWasm.dir/src/main.cpp.o
[ 66%] Building CXX object CMakeFiles/HelloWasm.dir/src/my_lib.cpp.o
[100%] Linking CXX executable HelloWasm
[100%] Built target HelloWasm
Obviously that did not create a .wasm file...
Doing the following:
em++ CMakeFiles/HelloWasm.dir/src/main.cpp.o CMakeFiles/HelloWasm.dir/src/my_lib.cpp.o -o helloWasm.js
output:
em++: warning: CMakeFiles/HelloWasm.dir/src/main.cpp.o is not a valid input file [-Winvalid-input]
em++: warning: CMakeFiles/HelloWasm.dir/src/my_lib.cpp.o is not a valid input file [-Winvalid-input]
em++: error: no input files
note that input files without a known suffix are ignored, make sure your input files end with one of: ('.c', '.i', '.cpp', '.cxx', '.cc', '.c++', '.CPP', '.CXX', '.C', '.CC', '.C++', '.ii', '.m', '.mi', '.mm', '.mii', '/dev/null', '.bc', '.o', '.obj', '.lo', '.dylib', '.so', '.a', '.ll', '.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH')
What am I missing here...?
Change:
em++ CMakeFiles/HelloWasm.dir/src/main.cpp.o CMakeFiles/HelloWasm.dir/src/my_lib.cpp.o -o helloWasm.js
To:
em++ CMakeFiles/HelloWasm.dir/src/main.cpp.o CMakeFiles/HelloWasm.dir/src/my_lib.cpp -o helloWasm.js
Emscripten can't compile my_lib.cpp.o because it's already compiled to machine code (it's an object file). You have to use a .cpp file, not .cpp.o.
I have a suggestion for you.
First, you can put your lib files (my_lib.h and my_lib.cpp) on same directory.
Second, you can create a folder for your applications (HelloWasm) and put your executable codes (main.cpp) in this folder.
Finally, you can create CMakeLists.txt file for each folder.
This is your new directory tree:
.
├── CMakeLists.txt
├── Applications
│ └── HelloWasm
│ ├── CMakeLists.txt
│ └── main.cpp
└── Libraries
├── CMakeLists.txt
├── my_lib.h
└── my_lib.cpp
CMakeLists.txt (the first one) :
cmake_minimum_required(VERSION 3.0)
project(LIBRARYANDAPPS)
#This function is starting build and looking all folders.
function( start_build )
file( GLOB_RECURSE components "${CMAKE_SOURCE_DIR}/*/CMakeLists.txt" )
foreach( component ${components} )
get_filename_component( path ${component} PATH )
add_subdirectory( ${path} )
endforeach( )
endfunction( )
start_build()
CMakeLists.txt (for HelloWasm):
#You can add Emscripten flags like this.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
-std=c++11 --bind \
-s USE_WEBGL2=1 -s FULL_ES3=1 --memory-init-file 0")
find_package(Eigen3 REQUIRED NO_MODULE)
include_directories(${EIGEN3_INCLUDE_DIR})
include_directories("${CMAKE_SOURCE_DIR}/Libraries")
ADD_EXECUTABLE(HelloWasm main.cpp)
TARGET_LINK_LIBRARIES(HelloWasm MyLib Eigen)
CMakeLists.txt (for Library):
find_package(Eigen3 REQUIRED NO_MODULE)
include_directories(${EIGEN3_INCLUDE_DIR})
ADD_LIBRARY(MyLib STATIC my_lib.cpp my_lib.h)
TARGET_LINK_LIBRARIES(MyLib Eigen)
With these edits, you can create bigger projects, libraries. And I think more useful like this.

add_custom_target not executing with multiple executable in a CMakeLists file

I got a situation where another Makefile is executed from a CMakeLists.txt file.
Here is my root directory structure.
.
├── client.cpp
├── CMakeLists.txt
├── proto_lib
│   ├── Makefile
│   └── math.proto
└── server.cpp
This is a simple grpc test code where I am trying to compile a proto files using a Makefile create a static library. And then link that library to the final targets in the CMakefile. Makefile is working fine. CMakefile is also working fine with one executable.
Here is the CMakefile:
cmake_minimum_required(VERSION 3.5)
project(client-server)
message(STATUS "Compiling Network Function : ${PROJECT_NAME}")
set(CMAKE_CXX_STANDARD 11)
message(STATUS "Project Directory: ${PROJECT_SOURCE_DIR}")
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
set(LIB_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto_lib/libmylib.a)
add_custom_target(libmylib.a ALL
COMMAND make
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/proto_lib
COMMENT "grpc headers and libraries are generating..."
)
add_executable(server server.cpp)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -g")
set(BASIC_LIBRARIES "-lpthread")
set(CMAKE_LINK_WHAT_YOU_USE ON)
set(LIBDIR "/usr/local/lib")
find_library(proto_location NAMES protobuf PATHS ${LIBDIR})
find_library(grpc_location NAMES grpc++ PATHS ${LIBDIR})
find_library(grpc_reflection_location NAMES grpc++_reflection PATHS ${LIBDIR})
find_library(dl_location NAMES dl PATHS ${LIBDIR})
find_library(grpc_location2 NAMES grpc PATHS ${LIBDIR})
if(proto_location)
message(STATUS "protobuf library found at " ${proto_location})
endif()
if(grpc_location)
message(STATUS "grpc++ found at " ${grpc_location})
endif()
if(grpc_reflection_location)
message(STATUS "grpc_reflection found at " ${grpc_reflection_location})
endif()
if(dl_location)
message(STATUS "dl found at " ${dl_location})
endif()
if(grpc_location2)
message(STATUS "grpc found at " ${grpc_location2})
endif()
target_link_libraries(server ${proto_location}
${LIB_FILE}
${grpc_location}
${grpc_reflection_location}
${dl_location}
${grpc_location2}
${BASIC_LIBRARIES}
)
When I enter the command make after CMake . in the root directory.
it starts with following output...
Scanning dependencies of target libmylib.a
[ 33%] grpc headers and libraries are generating...
[ 33%] Built target libmylib.a
etc.. etc..
and it succeeds.(The internal Makefile creates header files and static objects using proto and grpc libraries. After that server.cpp can include the headers from inside the proto_lib/ folder and CMake build succeeds)
But when I add one more executable at the end of CMakeLists.txt,
add_executable(client client.cpp)
target_link_libraries(client ${proto_location}
${LIB_FILE}
${grpc_location}
${grpc_reflection_location}
${dl_location}
${grpc_location2}
${BASIC_LIBRARIES}
)
and then cmake . && make
does not start with internal Makefile build. Instead, it starts with client build.
Scanning dependencies of target client
[ 20%] Building CXX object CMakeFiles/client.dir/client.cpp.o
/home/deka/Academic/gemini/learning/client_server_async/advanced1/client.cpp:10:10: fatal error: proto_lib/math.grpc.pb.h: No such file or directory
#include "proto_lib/math.grpc.pb.h"
Because proto_lib/Makefile is not executed first in this case therefore math.grpc.pb.h is not generated and that is what the above error is showing.
My question is: Why adding one more executable does not trigger the internal Makefile build at the start?
Thanks!