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

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.

Related

Integrating protoc/protobuf-cpp into a cmake project as "vendored dependency"

In a hobby C++ project, I use protobuf/protoc and the CMake function
find_package(Protobuf REQUIRED)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
"prj/proto/foo.proto"
)
to generate the C++ code from a .proto file.
I do not have a global installation of protoc, instead I use conan and a CMake module to obtain protobuf/3.11.4 from ConanCenter and compile it for the target architecture (if there is no suitable binary on CC already).
Now I would like to get rid of conan and supply protobuf sources directly with the project.
Naively, one could imagine to put the source folder in an "external" directory:
CMakeLists.txt
src\proto\foo.proto
src\main.cpp
external\protobuf-3.11.4
external\CMakeLists.txt
Where CMakeLists.txt contains
add_subdirectory(external)
and external\CMakeLists.txt contains
add_subdirectory(protobuf-3.11.4)
This apparently creates some chicken and egg problem, because the protobuf-config.cmake and protobuf-module.cmake files which provide protobuf_generate_cpp are not available prior the compilation of this external submodule and the cmake complains about not finding protobuf_generate_cpp.
I played a bit around with some hacks, but wonder what would be an appropriate way to solve this issue?

How to build many different packages with CMake

I'm trying to put together a CMake project where I have different packages that I need to build. This is my desired structure:
package1
src
file.cpp
test
file_test.cpp
package2
src
file2.cpp
test
file2_test.cpp
CMakeLists.txt
main.cpp // this will be removed later
This is my current CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(cppApp)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(${PROJECT_SOURCE_DIR})
# add the executable
add_executable(cppApp main.cpp ./package1/src/file.cpp ./package2/src/file2.cpp)
So the question is firstly, is a library considered a package in CMake? This question comes from someone who have done a lot of Java where I would typically call that a package and not a library. But does it in CMake?
Also, how do I in CMake include all files in the "packages" to be built instead of hard coding in the files as an executable? If I create many .cpp/.h files I want to automate this as much as possible.
I have seen that some other projects use a CMakeLists.txt file inside each "package", is this ideal? And is this good practice?
If you have a better suggestion according to some standard I should use to structure my project I would like to know a good one as well.
So the question is firstly, is a library considered a package in
CMake? This question comes from someone who have done a lot of Java
where I would typically call that a package and not a library. But
does it in CMake?
Your definition of package in Java is not quite accurate. Package is just a mean to organize classes in Java in namespace manner. It could be classes of a separate library, but nothing prevents you from using different packages within the same project. It has nothing to do with CMake packages, where each package is actually a whole separate project.
I have seen that some other projects use a CMakeLists.txt file inside
each "package", is this ideal? And is this good practice?
CMakeLists.txt files in subdirectories merely define new subset of rules for those directories. In order to make your CMake project respect those rules, you add such directory with add_subdirectory. It's not neccessarily a separate library, you can make subset of rules for parts of a single project, and it's usually a good idea to do that if some files are really that different.
CMake have something called add_library(lib) and is those kinds of directories considered a library?
add_library creates so-called CMake target, just like add_executable. The targets can be linked with each other with use of target_link_libraries, and that will indeed be considered a library in terms of C++.

Android Studio Compiles With Gcc, how to change that to G++ ? (Using CMake)

i have a Android studio project which uses Native C++ code with JNI, however when i try to Build my project, it throws error: undefined reference to 'std::basic_ostream<char...
errors.
I am using ubuntu and i believe the problem is caused by IDE using gcc compiler and tries to compile it as C code. When i try to run simple hello world program by running gcc -o foo foo.cpp in terminal, it gives same error. When i change gcc to g++, everything works fine.
But how do i change the compiler in IDE? I'm kinda new to using CMake and i think i need to use cmake's enable_language function but even i add enable_language(CPP) line to my CMakeLists.txt, it gives same errors.
Here is my CMakeLists.txt :
cmake_minimum_required(VERSION 3.4.1)
include_directories("/usr/include/x86_64-linux-gnu/c++/9")
include_directories("/usr/include/c++/9")
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("/usr/include")
file(GLOB srcs *.cpp *.c)
file(GLOB hdrs *.hpp *.h)
include_directories(${OpenCV_DIR}/jni/include)
include_directories(${TESSERACT_INCLUDE_DIRS})
include_directories(${LEPTONICA_INCLUDE_DIRS})
add_library( lib_opencv SHARED IMPORTED )
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${OpenCV_DIR}/libs/${ANDROID_ABI}/libopencv_java4.so)
add_library(
native-lib
SHARED
#
native-lib.cpp )
find_library(
log-lib
log )
target_link_libraries(
native-lib
lib_opencv
${log-lib}
${TESSERACT_LIBRARIES}
${LEPTONICA_LIBRARIES})
Thanks!
ps: My G++ and Gcc versions are 9.3.0, build-essentials are already installed.
Your CMakeLists.txt is a whole lot of mess. Lets go through some potential problems, one by one, and see if it starts working.
The solution is probably in point 7, but I already wrote it all so I am leaving it here. Let me know if my answer helped you.
1. Does Android Studio really use this CMakeLists.txt file for building?
There are two usual build systems for NDK - older ndk-build and newer CMake. Check your Gradle build file to see if this CMakeLists.txt is really used. Here is documentation about how it should work: https://developer.android.com/studio/projects/gradle-external-native-builds.
And of course, you can make a deliberate syntax error in your CMakeLists.txt file to see if the build systems starts complaining about it.
And note that CMake should not by invoked separately when building for Android. It should be invoked from inside the Gradle script that is used by Android Studio for building the whole project.
2. Do all source files that use C++ libraries have .cpp extension?
CMake determines what compiler to use (C or C++) based on the extension of the file. If it is a .c file, then C compiler is used. If it is a .cpp file, then C++ compiler is used.
Also note that Android NDK now uses Clang (from LLVM project) instead of GCC, so GCC version or custom GCC invocations might not be that relevant.
You can also make CMake verbose - to print all the build commands, to see which commands are exactly executed. Add set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON") to your CMakeLists.txt file to make it verbose.
3. Is correct C++ library used?
Symbols you are missing (something from std::basic_ostream) are defined in C++ library (I think) that needs to be linked to your library. By default, libc++ should be linked and that is the right choice. But there is an option that can mess with that. So check your gradle build file for a ANDROID_STL variable and remove any assignments to that variable. The issue of C++ library in NDK is explained here: https://developer.android.com/ndk/guides/cpp-support#cmake
4. Missing source files.
When you call add_library, you are only adding one source file - native-lib.cpp. So only this one file will be compiled in the library (apart from lib_opencv that is linked to it). The line file(GLOB srcs *.cpp *.c) assigns all cpp and c files to the ${srcs} variable but that variable is then left unused. You could change add_library to use that variable: add_library( native-lib SHARED ${srcs} ).
If you want to also include files from subdirectories, use GLOB_RECURSE instead of GLOB in your file(GLOB srcs *.cpp *.c) command.
The line file(GLOB hdrs *.hpp *.h) is completely useless as far as I can tell. I don't see how a list of all header files could be useful in a CMake script.
5. Use new target-based CMake configuration.
Older CMake used file-based configuration, now target-based configuration is encouraged. File-based commands are for example link_libraries and include_directories, their target-based alternatives are target_link_libraries and target_include_directories. You are mixing those two styles. Basically, when a command has its target_ variant, you always want to use it.
You need to first create your target using add_library( native-lib SHARED ${srcs} ), the targets name is native-lib. Then add all include directories and link all libraries to it using target-based commands.
Also the way you add lib_opencv is missing a find_package command. Use find_package(OpenCV REQUIRED) and then target_link_libraries( native-lib PUBLIC ${OpenCV_LIBS} ) to link it.
The way you are adding logging library is OK, because the log-lib library is part of native API (https://developer.android.com/ndk/guides/stable_apis#logging) so it is more straightforward.
With CMake, you need to search internet or documentation to find out, which commands are needed to add each library to your target (unless you are compiling the library from sources). Tthough it is almost always some combination of find_package and target_link_libraries.
6. Missing project information.
I am not sure how important that is, but usually you start your main CMakeLists.txt with something like this:
cmake_minimum_required( VERSION 3.4.1 )
project( my_special_project )
set( CMAKE_CXX_STANDARD 14 )
set( CMAKE_CXX_STANDARD_REQUIRED True )
7. Don't manually include system directories.
Thinking about it, this is probably the problem. Toss out all of these lines:
include_directories("/usr/include/x86_64-linux-gnu/c++/9")
include_directories("/usr/include/c++/9")
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("/usr/include")
Ndk uses its own toolchain, so never manualy add paths from your system toolchain to your NDK project.
I would discourage doing this also on any other project. It is not portable and things like that should be taken care of indirectly, by CMake itself.

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.

cmake - support of Visual Studio filters

I have a cmake file that generate a solution with several sub projects, but I wish a "filter" (VS specific feature) to group all my thirdparty libraries together.
An example, for now I use the ZLIB library, it appear as a project, I use the following:
add_subdirectory(zlib)
To add such filter, I have try the following :
add_subdirectory(zlib)
FILE(GLOB_RECURSE ZLIB_SOURCE "zlib/*")
SOURCE_GROUP("THIRDPARTY" FILES ${ZLIB_SOURCE})
In this example I wish to put the "zlib" project into a "THIRDPARTY" filter.
But nothing is changed in my solution ! I use VS2017 and cmake 3.8
Any idea ?
There are two ways of separating all your own and third-party code of an application in the solution explorer.
Separate multiple Projects and put them into folders which are on top-level.
Do the following:
put this on top of your main CMakeLists.txt
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
after defining your targets add this extra bit
add_executable(MyLib .....)
set_target_properties(MyLib
PROPERTIES
FOLDER "Libraries");
Your project-explorer will then look like this:
credit goes to these guys: http://cmake.3232098.n2.nabble.com/Solution-folders-td6043529.html
To separate multiple source-files inside a project you can do the following:
collect all files of a module with:
set(VARIABLE_NAME src/module/fileName1.cpp
src/module/fileName2.cpp)
make it appear within a filter:
source_group("Source Files\\module" FILES ${VARIABLE_NAME})
group all previously generated filters together:
set(SOURCE_FILES "${VARIABLE_NAME}")
finally make everything appear inside the project explorer:
add_executable(projectName "${SOURCE_FILES}")
The above works for me under CMake 3.6 and Visual Studio 2015, so it should also work with VS2017 and Cmake 3.8.
It looks like this when finished for all files of the project:
Since you are developing with VS here's another hint that I think is very useful:
you can define VS's startup project by the following command. This way you don't have to change anything in VS after remaking the project with CMake.
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ProjectName)