I have a static library (openexr.lib) that was compiled in debug mode. I'm trying to link this library to a project I've created using CMake. Here's my folder structure.
+-- myproject
| +-- Demo
| +-- build
| +-- libraries
| +-- openexr.lib
| +-- cmake
| +-- GenerateVS2015.bat
| +-- CMakeLists.txt
| +-- Demo.cpp
| +-- stdafx.cpp
So, you can see that I have the openexr.lib located in the libraries directory. I have verified that this .lib file has been compiled as a static library and the file size is approximately 64mb. Then, I have a batch file which is found in the cmake directory which tries to build the projects. Here's what my batch script looks like.
#echo off
set startingDir=%CD%
set basepath=%~dp0
set builddir=%basepath%\..\build
if exist %builddir% (#RD /S /Q %builddir%)
mkdir %builddir%
cd %builddir%
cmake -G "Visual Studio 14 2015 Win64" .. %*
cd %startingDir%
So, this basically creates the build directory if it doesn't already exist (otherwise it clears it so it can repopulate everything). Then, it calls the cmake command with the visual studio generator option.
Now, here's what's in my CMakeLists.txt file:
CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
PROJECT (MyProject)
IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
ADD_DEFINITIONS(-DBUILD_DLL)
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} xmllite.lib")
string(REGEX REPLACE "/bin/[^/]*$" "" VCINSTALLDIR "${CMAKE_C_COMPILER}")
message(STATUS "Guessed MSVC directory: ${VCINSTALLDIR}")
ENDIF()
ADD_LIBRARY(openexr STATIC IMPORTED GLOBAL)
SET_TARGET_PROPERTIES(openexr PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libraries/openexr.lib)
ADD_EXECUTABLE(MyDemo ${CMAKE_CURRENT_SOURCE_DIR}/Demo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/stdafx.cpp)
TARGET_LINK_LIBRARIES(MyDemo openexr)
When I run my batch file, it generates the MyDemo.vcxproj file correctly. I can see it's setup to compile with the target extension .exe (which is what I want). But, when I try to build the project, I get the following error message:
C:\myproject\build\Debug\MyDemo.exe : fatal error LNK1120: 78 unresolved externals
If I open up the property pages for my demo project, I can see that under the Linker section that is trying to link to my openexr.lib file.
But, for some reason it continues to fail every time I try to build the executable file. Can anyone provide a reason why?
EDIT
Here is a link to the full error log in case it helps: errorlog.txt
Related
I am attempting to integrate a C++ library I downloaded into a new project using CMake.
I downloaded the library ("downloaded_library"), created the build folder, and inside of it ran cmake .. and make. These both ran successfully, and than I navigated to the build folder and ran ./example to run the example file that came with the library. This also was successful, and so I hoped to add it to another project.
I added this working project into the 'libraries' folder of the following directory structure:
project
-libraries
-downloaded_library
-build
-include
-downloaded_lib
-downloaded_lib.h
-src
-examples
-example.cpp
-CMakeLists.txt
-src
-main.cpp
-build
-CMakeLists.txt
I hope to run the same code that ran in example.cpp in main.cpp, but I have been unable to get the import working. I navigate to the build folder and cmake .. runs successfully, but 'make' fails with an import error (fatal error on the include line, can't find the header file). This makes sense, as I didn't expect the same include line to work (I copy and pasted example.cpp to main.cpp), but I'm not sure what to make that.
fatal error: downloaded_lib/downloaded_lib.h: No such file or directory
1 | #include "downloaded_lib/downloaded_lib.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
In this situation, what should my CMakeLists.txt contain, and what should my #include contain to be able to use the contents of this library in main.cpp in the same way I can in example.cpp?
EDIT---
I changed the package names above for simplicity sake, but the repository of 'downloaded_library' is the following: https://github.com/siposcsaba89/socketcan-cpp.
My top level CMakeLists.txt looks like this:
# Minimum version of CMake required to build this project
cmake_minimum_required(VERSION 3.0)
# Name of the project
project(projectname)
# Add all the source files needed to build the executable
add_executable(${PROJECT_NAME} src/main.cpp)
add_subdirectory(libraries/downloaded_library)
# Link the executable and the library together
target_link_libraries(${PROJECT_NAME} downloaded_library)
Edit 2-- (Here I will use the original package name, socketcan-cpp).
Top level CMakeLists.txt:
# Minimum version of CMake required to build this project
cmake_minimum_required(VERSION 3.0)
# Name of the project
project(socketcan_demo)
# Add all the source files needed to build the executable
add_executable(${PROJECT_NAME} src/main.cpp)
add_subdirectory("libraries/socketcan-cpp")
target_include_directories(${PROJECT_NAME} PUBLIC "libraries/socketcan-cpp/include")
When running make I get this error:
fatal error: socketcan_cpp/socketcan_cpp_export.h: No such file or directory
4 | #include <socketcan_cpp/socketcan_cpp_export.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
So the top level CMakeLists is able to find the header file located in include, but that header file contains the line: #include <socketcan_cpp/socketcan_cpp_export.h> which references a file in a gen directory inside the build directory created by the library's CMakeLists.txt (https://github.com/siposcsaba89/socketcan-cpp/blob/master/CMakeLists.txt). And my top level package is unable to find it.
In order to include the header files from the downloaded library, you can add the following to the CMakeLists.txt file:
find_library(downloaded_lib
NAMES downloaded_lib
HINTS "path to downloaded lib file")
if(NOT downloaded_lib)
message(FATAL_ERROR "downloaded_lib not found!")
endif()
target_include_directories(${PROJECT_EXECUTABLE} PUBLIC "path to download_lib.h")
target_link_libraries(${PROJECT_EXECUTABLE} ${downloaded_lib})
This includes the directory where the header file is located in addition to the library file.
Basically I wanted to learn CMake and GTest. On top of that I wanted to try out CI's and I have added my simple project to Travis CI and AppVeyor. The project compiles well on my local machine (tested with vs 2017 and g++, not sure about the versions, because I am not near it at the moment) as well as on AppVeyor.
The project consists of a few headers compiled to a static library, executable for "manual testing" the static library and gtest (no tests at the moment, just a template).
The structure looks like that:
.
+-- .appveyor.yml
+-- .travis.yml
+-- CMakeLists.txt
+-- main
| +-- main.cpp [The manual testing exec]
| +-- CMakeLists.txt
+-- include
| +-- Utility.h
| +-- CMakeLists.txt
| +-- Other header files to compile to static library
+-- test
| +-- CMakeLists.txt
| +-- CMakeLists.txt.in
| +-- testutility
| | +-- main.cpp [sample exe file for gtest, not used yet]
| | +-- CMakeLists.txt
During build on Travis CI, it cannot find headers for the static library.
I have tried using
include_directories(".") on main CMakeLists.
Main CMakeLists.txt
cmake_minimum_required (VERSION 3.1)
project (primlibrary)
enable_testing()
include_directories(".")
add_subdirectory(include)
add_subdirectory(main)
add_subdirectory(test)
Travis CI error message
CMake Error at include/CMakeLists.txt:12 (add_library):
Cannot find source file:
Utility.h
Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx
-- Generating done
-- Build files have been written to: /home/travis/build/SoIAS/PrimLibrary/build
The command "cmake .." exited with 1.
$ make
Scanning dependencies of target prim_library
[ 9%] Linking CXX static library libprim_library.a
[ 9%] Built target prim_library
Scanning dependencies of target manualtestingapp
[ 18%] Building CXX object main/CMakeFiles/manualtestingapp.dir/main.cpp.o
/home/travis/build/SoIAS/PrimLibrary/main/main.cpp:2:29: fatal error: include/Utility.h: No such file or directory
#include "include/Utility.h"
And include/CMakeLists.txt:
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(prim_library_srcs
ForwardList.h
LinkedList.h
Utility.h
tempfix.cpp
)
add_library(prim_library STATIC ${prim_library_srcs})
set_target_properties(prim_library PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(prim_library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
CI and git links:
- Travis CI last build
- Appveyor build
- Github
Do you know what am I doing wrong?
The problem was solved literally a dozen minutes after posting. The Utility.h file locally had capitalized first letter while the one on git was lower case. It was solved by using git command to capitalize the first letter of the file on git:
git mv include/utility.h include/Utility.h
I have a batch script which when run will simply call a cmake command to build a visual studio C++ project. However, that project should have two references to two static libraries... yet, no matter what I try I can't seem to get my project to link the libraries correctly. Here's how my folder structure looks:
.
+-- build
| +-- x64
| +-- DebugStatic
| +-- mylibA_static.lib
| +-- mylibB_static.lib
+-- Include
+-- Source
+-- myproject
| +-- Demo
| +-- build
| +-- cmake
| +-- GenerateVS2015.bat
| +-- CMakeLists.txt
| +-- Demo.cpp
| +-- stdafx.cpp
Now, I'm running the batch script from within the cmake folder inside the Demo project folder structure. My batch script is as follows:
#echo off
set startingDir=%CD%
set basepath=%~dp0
set builddir=%basepath%\..\build
if not exist %builddir% (mkdir %builddir%)
cd %builddir%
cmake -G "Visual Studio 14 2015 Win64" .. %*
cd %startingDir%
Nothing too complicated. Now, let's look at the CMakeLists.txt file:
cmake_minimum_required (VERSION 2.8)
PROJECT (Demo)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
add_definitions(-DBUILD_DLL)
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} xmllite.lib")
string(REGEX REPLACE "/bin/[^/]*$" "" VCINSTALLDIR "${CMAKE_C_COMPILER}")
message(STATUS "Guessed MSVC directory: ${VCINSTALLDIR}")
endif()
SET(SRCS
Demo.cpp
stdafx.cpp
)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ../../Include)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibA_static.lib ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibB_static.lib)
Using this logic, wouldn't CMake build a Visual Studio C++ project called Demo.vcproj... and inside that project file would linked two libraries called mylibA_static.lib and mylibB_static.lib inside the references. However, when I try this, I never get any sort of linked library.
First, in your batch script, you only generated the makefiles, but you didn't actually build the library. So I would suggest you add the line make after cmake and before cd.
Second, I would suggest you surround all your strings with double quotes, in order to be specific, and avoid confusion between constants and variables. Also, it is better to add additional slashes. So, change
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibA_static.lib ${CMAKE_CURRENT_SOURCE_DIR}../../build/x64/DebugStatic/mylibB_static.lib)
to
TARGET_LINK_LIBRARIES(${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/../../build/x64/DebugStatic/mylibA_static.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../../build/x64/DebugStatic/mylibB_static.lib)".
As for the relative pathes, I think you are fine. But be careful when you use CMAKE_SOURCE_DIR and CMAKE_CURRENT_SOURCE_DIR. Here are some notes from CMake Wiki:
CMAKE_CURRENT_SOURCE_DIR this is the directory where the currently
processed CMakeLists.txt is located in
CMAKE_SOURCE_DIR this is the directory which contains the top-level
CMakeLists.txt, i.e. the top level source directory
I am trying to learn OpenGL and would like to set up my build environment with cmake. I will use GLEW (OpenGL Extension Wrangler) and freeglut. However there is one problem... Since I am an absolute beginner to "project management" in C++ and cmake I am having hard time pointing to static libraries. I can understand C++ code but compeletly new to C++ based project build systems.
I am just simply trying to generate a Visual Studio 2015 project. My question is: How can show my static libraries to cmake. My project folder structure:
build # Folder where I would like cmake generated files to be generated in this directory.
include
|-- GL
| |-- freeglut.h
| |-- freeglut_ext.h
| |-- freeglut_std.h
| |-- glut.h
|-- glew
| |-- eglew.h
| |-- glew.h
| |-- glxew.h
| |-- wglew.h
lib
|-- freeglut.lib
|-- freeglut_static.lib
|-- glew32.lib
|-- glew32s.lib
src
|-- main.cpp
CMakeLists.txt
My CMakeLists.txt file is as following:
cmake_minimum_required(VERSION 2.8)
project(sb7application)
find_package(OpenGL REQUIRED)
find_library(LINK_LIBS NAMES freeglut freeglut_static glew32 glew32s PATHS lib)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} ${LINK_LIBS} ${OPENGL_LIBRARY})
Here, basicly what I want to do is to ask CMake to link static libraries in the lib folder. However this cmake script doesn't add the Linker input configuration to my visual studio project settings. For example, if I open the generated visual studio project and go to Properties > Linker of the project and add this lib directory to additional library directories and specify the libraries (.libs) in Properties > Linker > Input section, it compiles successfuly. Otherwise, it gives a linkage error saying something like '__imp_glewInit()' cannot be found.
Yeah, how can I show this lib directory and its contents as my static libraries to be linked? If you can explain like you explain to a child and explain each step in detail, I would be greatly appriciated.
I have a project with the following structure
+--foo/
|
+-- CMakeLists.txt
+-- src/
+-- include/
+-- third-party/
|
+-- thing.tar.gz
An step of the build process is to inflate and untar thing.tar.gz, build it using CMake, and once that is ready proceed to compile and link whatever is under src (my actual project).
I would like all of this to be done out of source, in a build directory. Ultimately I would like my build process to be as follows:
$ cd /path/to/where/I/want/to/build/
$ cmake /path/to/directory/containing/CMakeFiles.txt/
$ make
# make inflates, untars, and builds thing.tar.gz
$ ls
# lists all the CMake stuff and the following folders:
# bin/ -> with all my application AND thing.tar.gz executables
# lib/ -> with all my libraries AND thing.tar.gz libraries
# include/ -> with all my headers AND thing.tar.gz headers
For the life of me, I cannot find a simple solution! So far, I am able to rely on EXECUTE_PROCESS to extract to a folder in the build tree, but I cannot call CMake on the resulting library, or to inform the rest of my project hey, I extracted and built your dependencies [here] and [there]; you can carry on building now.
How would you address this problem?
Use -DCMAKE_PREFIX_PATH= to point cmake to where your dependencies' build artifacts are installed to during your own project's cmake invocation.