working with c++ library's source code (opencv) - c++

I want to ask if it is possible to work with c++ source code of the opencv library, without using the compiled libraries like .lib and .dll.
I mean is it possible to work only with header files and .cpp files from the library?
I want to create a basic c++ class with a function that accepts an image and perform a series of opencv related operations, but I need the freedom to compile the code for a number of platforms as a native library (and I think that using .lib or .dll will forbid the compilation for several platforms). I guess that could be possible by using only the c++ source code. But using visual studio and adding Additional Include Directories, I do get errors LNK2019, that is probably "A function or variable is declared but not defined" although I do include the 'right' directories with .hpp's and .cpp's but probably I miss something.

This is a typical case for native code. What you need to do is download the source code (I believe you have already done that) and build it separately for platform(s) you need it for.
In your project include the result libraries (either static lib or dynamic dll files) as you would pre-compiled ones. This way library files are kept separate and built only once, not on every build of your project.
In Visual Studio you can set the include path separately for every configuration so you can set your project up to use library built for current architecture.

Adding to what #slawekwin wrote in his comment above, building and
linking dependencies on your target platforms can also be automated as
part of your build system.
If you built OpenCV before, you should have come across CMake. With
CMake it's possible to configure external projects (EP), which will
download source code of third party project and then configure, build,
and install it. This is an example for OpenCV copied from a github
repository:
ExternalProject_Add(opencv
GIT_REPOSITORY ${git_protocol}://code.opencv.org/opencv.git
GIT_TAG 2.3.1
SOURCE_DIR opencv
BINARY_DIR opencv-build
UPDATE_COMMAND ""
PATCH_COMMAND ""
CMAKE_GENERATOR ${gen}
CMAKE_ARGS
${ep_common_args}
-DBUILD_DOCS:BOOL=OFF
-DBUILD_EXAMPLES:BOOL=OFF
-DBUILD_NEW_PYTHON_SUPPORT:BOOL=OFF
-DBUILD_PACKAGE:BOOL=OFF
-DBUILD_SHARED_LIBS:BOOL=ON
-DBUILD_TESTS:BOOL=OFF
# -DCMAKE_BUILD_TYPE:STRING=Release
-DWITH_FFMPEG:BOOL=OFF
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/INSTALL
)
set( OPENCV_ROOT_DIR ${CMAKE_BINARY_DIR}/INSTALL )
set( OPENCV_DIR ${CMAKE_BINARY_DIR}/INSTALL )
It could also be interesting to take a look at a cross-platform package
manager for C++ called hunter, which is based on CMake EP.

Related

Correct way to build OpenCV as a third party library along with your project in CMAKE

I have a C++ project, where I use opencv, VTK. I would like to build and install these dependent libraries (opencv,vtk) automatically, which are situated in my thirdparty project folder. I know that opencv and VTK use cmake build system to build their libraries. I even saw the function ExternalProject to add them to my CMakesLists.txt but I had problem of linking the target with opencv libs.
Searching on stack overflow I could not find a proper defined method to do it to implement this for version 3.0, the proposed solutions where Version < 3.0. I would like to know how you will structure your project to build opencv automatically as a thirdparty library, exports its targets and link it with my project target.
I think that the best way is to look for what's being done on larger project on github. I would advise to look at this repo in which they use opencv version 3.2, automatically download it and compile it. I believe that this is the correct way because you just have to change the version to try the compatibility with the newer versions if you want to update your code.
What you are looking for is probably what is called a superbuild. This post might help.
I would suggest to build and install opencv in a subfolder of your repo or your build directory. Then you could set the OpenCV_DIR environment variable to the <opencv_install_prefix>/lib/cmake/opencv4 folder (or at least point to the folder where OpenCVConfig.cmake is)
Then in your CMakeLists.txt you can directly use :
find_package(OpenCV 4 REQUIRED
COMPONENTS core imgproc ximgproc)
target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS})
The OpenCV_DIR variable tells CMake where to find the OpenCV configuration files needed for find_package function.
For the build and installation step, you could use ExternalProject or FetchContent (I prefer the later) but since OpenCV could be very long to build, you might want to keep the build artifact outside of your project's build folder. Then you can erase your build folder to rebuild your project without rebuilding the whole OpenCV library.
On my side, I'm using a shell script that build OpenCV if needed before building the project that needs it.

How to include source of external library for IntelliSense in a CMake project?

I am working on a C++ application in Visual Studio, using the Visual Studio's CMake project template.
To build my application I only need the header and the external library and I can link it like this:
# CMakeList.txt : CMake project for myapp, include source and define project specific logic here.
cmake_minimum_required (VERSION 3.8)
# Add source to this project's executable.
add_executable (myapp "myapp.cpp" "myapp.h")
# Add TIFF library
set(TIFF_INCLUDE_DIR "C:\\libs\\tiff\\out\\install\\x64-Debug\\include")
set(TIFF_LIBRARY "C:\\libs\\tiff\\out\\install\\x64-Debug\\lib\\tiffd.lib")
find_package(TIFF REQUIRED)
target_link_libraries(myapp PRIVATE TIFF::TIFF)
So far, so good. I can use the tiff library to open, read, write tiff files, etc., and IntelliSense is catching up with declarations in the header files. But, I would like IntelliSense to also be aware of the full source code of the TIFF library. For example, if I am in myapp.cpp and I ctrl+click on TIFFOpen it opens the header corresponding to TIFFOpen, but when I ctrl+click TIFFOpen in the header file, it doesn't go to the corresponding source file, which is the normal behaviour for source files in myapp. This is understandable, since I never told Visual Studio where to find the source files of the external library.
CMake doesn't need to know where the source files of the external libraries are, since it won't build the external library, therefore I guess I don't/shouldn't change anything in CMakeLists.txt
One option (I haven't tried yet, but I'm fairly sure it would work), would be to just include the entire tiff library as a sub-project of myapp. I do have some problems with this solution though:
The external library is not conceptually an integral part of the project, and I don't plan to modify the external library. This is more of a principle issue.
Simply having it as a subfolder in my project makes it a risk of changing something I didn't intend to change.
I don't want to rebuild the external library when I do a rebuild all. I know Visual Studio / CMake is smart enough to figure out that nothing changed and doesn't rebuild, but I would rather have Visual Studio / CMake not even try.
The way I see it, I have to set the directory with the source files somewhere in Visual Studio settings, but still related to the project. My best guess is that the .vs/ProjectSettings.json is the file I need to edit somehow, but honestly, I have no clue.
Alternatively, maybe I could write some command in CMakeLists.txt that doesn't do anything, but triggers the IntelliSense to look in the folder with source files. Again, I have no clue how should I go about this.
In a nutshell, I want IntelliSense to see all source files of an external library, the same way it sees the source files of myapp, without including all source files of the external library as a sub-project of myapp. How should I go about it, if even possible?
If relevant, I use Visual Studio 2019 Community and the CMake it comes with it (3.15).
Regarding your last comment, writing code in comment section is inconvenient so I'll just post it here although not an answer.
libtiff-4.pc is for pkg-config, not cmake, and find_package() can't deal with it directly on Windows and would take some work if you really want to. It might be easier to just write everything manually. Remember to set the tiff.lib and tiffd.lib according to your configuration. You can use CMAKE_BUILD_TYPE variable and if() command such as:
# set build type to release if not specified
if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
endif()
# switch lib to link according to build type
if(CMAKE_BUILD_TYPE STREQUAL "Release")
# for release
set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiff.lib")
else()
# for debug. If you have other configs like relwithdebinfo you can add more
set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiffd.lib")
endif()
Also, remove find_package() and use target_link_libraries() and target_inlude_directories():
set(TIFF_INCLUDE_DIR "<your_path_to_installed_headers>/include")
target_link_libraries(myapp PRIVATE ${TIFF_LIBRARY})
target_include_directories(myapp PRIVATE ${TIFF_INCLUDE_DIR})
You can also skip setting TIFF_LIBRARY and TIFF_INCLUDE_DIR and pass the string directly if you like.
I use Visual Studio a lot and it's my favorite IDE. But package management with cmake on Windows is not as smooth as Linux. Always remember to set environment variables after compiling and installing external libraries.
Normally find_package() will look for a system environment variable named <libname>_DIR (for example TIFF_DIR, which is not found in your case), which is used to store path to installed lib, then look for <libname>Config.cmake and <libname>ConfigVersion.cmake in that folder (and would fail for TIFF since it doesn't have them).
It also searches other places, check https://cmake.org/cmake/help/v3.15/command/find_package.html?highlight=find_package for details.
So for those libs with cmake exported files, add a variable with correct name and value. And that's only for compiling.
If you want your application to run after compiling, you also need to add the path of installed lib's binaries (usually *.dll) to system's Path variable. In your case you should find something like tiff.dll and tiffd.dll after compiling and installation, add that folder to Path and you are good to go.
Actually, showing the source in the IDE is easy enough.
Just add the source with add_library(tiff_for_ide EXCLUDE_FROM_ALL ${SOURCES}) but don't link with it in the main program. You'll want to use a different target name for the library. For this you'd need the source in your project directly or as a submodule (if using Git, something else if available by you VCS).
Other options are using ExternalModule_Add; or FetchContent_MakeAvailable with the add_library as above, to avoid adding third party deps into the repository directly.
Now, just cross your fingers and hope that the IDE is not intelligent enough to restrict searching for sources that are linked against the target which compiles the current file. Or that it's intelligent enough to detect this situation but fallback to searching the whole project files anyway when it's linking against a binary.

Generating dll from an existing code on Windows using CMake and VS

I have downloaded an SDK written in C++ (OPC UA) that creates a .exe file on compiling with Visual Studio 2015. It has a bunch of CMake files. How could one see if it is possible to generate a .dll from such an SDK? Do the CMake files have this information or should there be any macros inside the headers I would have to search for ? The SDK has Visual Studio sample projects (.sln) that I am using to create .exe.
The CMakeLists.txt looks like this
project(uasdk)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
include(CMakeDependentOption)
include(MessageUtils)
display_project_header("true")
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src")
add_subdirectory(src)
endif ()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples")
add_subdirectory(examples)
endif ()
# set CMAKE_INSTALL_MESSAGE to LAZY by default to hide 'Up to date' output when building INSTALL target
if (NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
set(CMAKE_INSTALL_MESSAGE LAZY CACHE STRING "")
set(CMAKE_INSTALL_MESSAGE_VALUES "ALWAYS;LAZY;NEVER")
set_property(CACHE CMAKE_INSTALL_MESSAGE PROPERTY STRINGS ${CMAKE_INSTALL_MESSAGE_VALUES})
endif ()
The questions that already have been asked regarding this topic are from the people who are writing their own code. I intend to use the code from the SDK. Apart from changing the CMAKE file to include the dll do I need to make changes in the source code as well?
It has a bunch of CMake files. How could one see if it is possible to generate a .dll from such an SDK? Do, the CMake files have this information or should there be any MACROS inside the headers I would have to search for ?
If the CMake project generates a library, then the statement add_library must appear somewhere. Note, however, that hierarchies of CMakeLists.txt files are possible, for example, the CMakeLists.txt you included adds two subdirectories. Consider the CMakeLists.txt files in there as well. Since an executable is generated, a call to add_executable must appear somewhere as well.
I intend to use the code from the SDK. Apart from changing the CMAKE file to include the dll do I need to make changes in the source code as well?
I am not familiar with this SDK, but I would guess that examples contains the sources for the executable and src contains the sources for a library. If you just want to try something out, you can modify the example code or add a new example. In this case, you only have to modify the CMakeLists.txt in the examples directory (i.e., add your new source code file).
If you want to use the SDK as external dependency, check whether there is a FindNameofmySDK.cmake included in the CMake modules list or whether there is a NameofmySDK-config.cmake somewhere in the SDK sources or your installation. In this case, you can create a CMake project for your application and use find_package to look for the SDK.

Embedding library and it's includes via CMake

I'm creating a very small project that depends on the following library: https://github.com/CopernicaMarketingSoftware/AMQP-CPP
I'm doing what i always do with third-party libraries: i add their git repo as a submodule, and build them along with my code:
option(COOL_LIBRARY_OPTION ON)
add_subdirectory(deps/cool-library)
include_directories(deps/cool-library/include)
target_link_libraries(${PROJECT_NAME} coollib)
This has worked perfectly for libraries like Bullet, GLFW and others. However, this AMQP library does quite an ugly hack. Their include directory is called include, but in their CMake install() command, they rename it to amqpcpp. And their main header, deps/cool-library/amqpcpp.h, is referencing all other headers using that "fake" directory.
What happens is: when CMake tries to compile my sources which depend on deps/cool-library/amqpcpp.h, it fails because it's not finding deps/cool-library/amqpcpp/*.h, only deps/cool-library/include.
Does anyone have any idea how i can fix this without having to bundle the library into my codebase?
This is not how CMake is supposed to work.
CMake usually builds an entire distributive package of a library once and then installs it to some prefix path. It is then accessible for every other build process on the system by saying "find_package()". This command finds the installed distibution, and all the libs, includes etc. automagically. Whatever weird stuff library implementers did, the resulting distros are more or less alike.
So, in this case you do a lot of unnecessary work by adding includes manually. As you see it can also be unreliable.
What you can do is:
to still have all the dependencies source distributions in submodules (usually people don't bother doing this though)
build and install each dependency package into another (.gitignored) folder within the project or outside by using their own CMakeLists.txt. Let's say with a custom build step in your CMakeLists.txt
use "find_package()" in your CMakeLists.txt when build your application
Two small addition to Drop's answer: If the library set up their install routines correctly, you can use find_package directly on the library's binary tree, skipping the install step. This is mostly useful when you make changes to both the library and the dependent project, as you don't have to run the INSTALL target everytime to make library changes available downstream.
Also, check out the ExternalProject module of CMake which is very convenient for having external dependencies being built automatically as part of your project. The general idea is that you still pull in the library's source as a submodule, but instead of using add_subdirectory to pull the source into your project, you use ExternalProject_Add to build it on its own and then just link against it from your project.

How can I add libraries to a project in a system independent way?

I'm developing an application using Qt and OpenGL, and found it necessary to download the GLM library. It's a header-only library, so I don't need to link to anything. I want this application to build on any system that has the correct libraries installed. My problem is that I don't know where to put GLM so that the system can find it without adding a specific path to the project's .pro file. The .pro file is part of my git repository, which is how the source is distributed to other systems like Linux, etc. So I don't want this file to specify the exact location of GLM because other systems could have it in other places.
I'm currently developing on Windows, compiling in Qt Creator using Visual C++ 2010. I read from MSDN that #include <file> searches using the INCLUDE environment variable, so I tried to add the path to glm.hpp to INCLUDE, but QtCreator's build environment for this project seems to overwrite INCLUDE. So I appended the path to GLM to the new INCLUDE from within QtCreator's Projects tab, but my code still can't find glm.hpp.
In general, how can I add an external library to my system such that my compiler will be able to find it without specifying the exact location in a project file that's distributed to other systems?
What you need is a build system with the power to search the system for the libraries you request, and be able to do so on any platform. One such build system is cmake, and it is the most widely used build system. In essence, cmake allows you to write a build script in which you can specify all the things you normally specify when creating a project in Qt Creator or Visual Studio, like the list of source files, grouped by targets to compile (libraries, executables, etc.), the relative paths to the headers, and libraries to include for linking and for include-paths, amongst many more things. For libraries that are installed on the system, there is a function, called find_package() (part of cmake script commands), that will find out if the library is installed and where to find its lib files and headers (storing those paths as cache strings that you can specify on the targets and such). It usually works great, as long as the libraries are not installed in weird places. The way it works is that when you run cmake, it will generate a build script/configuration for almost any platform you specify, and then you use that to compile your code. It can generate makefiles (Unix-like or windows), CodeBlocks project files, Visual Studio project files, etc.. And many IDEs also have native support for cmake projects.
I wish I could recommend an alternative, just to sound less biased for cmake, but I haven't heard of any that truly compare to it, especially for the purpose of locating external dependencies and working with different platforms. I would guess Boost.Build is decent too.