Using CMake targets in Visual Studio projects - c++

I am pretty comfortable with CMake when used in Linux. That is, I use CMake to logically group my code into "targets" and abstract such things as "include directories" and other dependencies. Say, inside a large project my modus operandi would be to add_library(..SHARED) for a bunch of related files that provide one logically coherent unit, and target_link_libraries(...) to it from somewhere else.
(Of course, idiosyncrasies of CMake is another topic. I won't digress to discussions about e.g. its syntax.)
Now, for Windows 10. I fired up Visual Studio 2019 Community with the MSVC toolchain (that is, not WSL/WSL2), and created a CMake Project using VS's "New Project" wizard.
It has created for me some boilerplate code, and the whole project tree looks as below:
In this image, EnRouteGeneratedLibrary is something I added as the next step. Inside it, I have one *.hpp file:
#pragma once
template<typename T>
class __declspec(dllexport) SampleTemplateKlass {
public:
T sum(T x, T y) { return x + y; }
};
template class __declspec(dllexport) SampleTemplateKlass<int>;
and the CMakeLists.txt's contents are as follows:
add_library(${TRG} SHARED ${CMAKE_CURRENT_SOURCE_DIR}/SampleTemplateKlass.hpp)
# set_target_sources(${TRG} PUBLIC SampleTemplateKlass.hpp)
set_target_properties(${TRG} PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(${TRG} PUBLIC .)
set(WINDOWS_EXPORT_ALL_SYMBOLS 1)
Finally, in when building a simple "Hello World" executable, I have the following:
//
#include "SampleProjectWithDll.h"
#include "SampleTemplateKlass.hpp"
using namespace std;
int main()
{
cout << "Hello CMake." << endl;
SampleTemplateKlass<int> tmp;
std::cout << tmp.sum(42, 314) << std::endl;
return 0;
}
(This is the boilerplate code created by VS + my additions).
I link as follows:
# CMakeList.txt : CMake project for SampleProjectWithDll, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
add_subdirectory(EnRouteGeneratedLibrary)
# Add source to this project's executable.
add_executable (SampleProjectWithDll "SampleProjectWithDll.cpp" "SampleProjectWithDll.h")
target_link_libraries(SampleProjectWithDll PUBLIC SampleLibrary)
# TODO: Add tests and install targets if needed.
When building all this, I get two errors,
LNK2001 unresolved external symbol _DllMainCRTStartup and LNK1120 1 unresolved externalswith SampleLibrary.dll in the "File" field of the error panel.
The question is, how to make this simple "Hello World" compile and execute under Windows,
using the CMake infrastructure?

Related

Error LNK1112 when compiling a simple C++ program that include PyBind 11

I encountered the following error when trying to compile a simple test C++ program that includes pybind11.h (shown as follows)
The errors are:
"Error- LNK1112 module machine type 'x86' conflicts with target machine type 'x64' "
My test code is:
#include <iostream>
#include <Aspose.Cells.h>
#include <pybind11/pybind11.h>
void print(const char*);
int add(int i, int j) {
return i + j;
}
//PYBIND11_MODULE(example, m) {
// m.doc() = "pybind11 example plugin"; // optional module docstring
// m.def("add", &add, "A function which adds two numbers");
//}
int main()
{
const char *x = "C Plus plus.";
string xx = string(x);
char *z;
char b = 'z';
z = &b;
int num = 10;
int* a = 0;
print(x);
//std::cout << "Hello!!\n";
}
void print(const char* z)
{
std::cout << "pointer z is" << z << "\n";
}
I thought I need to change the target architecture, so I made the changes as shown in the screenshot below, but I still couldn't compile. Instead of receiving the previous error message, the error became a red curly line under "#include <pybind11/pybind11.h>, where it warned "cannot open source file "pybind11/pybind11.h"".
If I I reverse all changes that were shown in the screenshots (back to W32), it compiles. But only if I "commented out" the lines for PYBIND11_MODULE. I need to use Pybind11.h , so being able to compile without the line for PYBIND11_MODULE., is not useful for me.
Can someone please help? Thank you SO MUCH in advance!
I solved my problem by following the instructions listed on the following webpage, in addition to the steps I mentioned in my original post concerning changes of target architecture:
https://github.com/Microsoft/python-sample-vs-cpp-extension
specifically the following two steps:
1)C++ > General > Additional Include Directories :
Property must point to the "include" folder of your Python installation.
2)Linker > General > Additional Library Directories:
Property must point to the "libs" folder of your Python installation.
For the benefits of other people who migh ran into same problems as me, below is another good list of instructions which I referred to additionally, and I found it on https://learn.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2019
Unable to locate Python.h (E1696: cannot open source file "Python.h" and/or C1083: Cannot open include file: "Python.h": No such file or directory): verify that the path in C/C++ > General > Additional Include Directories in the project properties points to your Python installation's include folder. See step 6 under Create the core C++ project.
Unable to locate Python libraries: verify that the path in Linker > General > Additional Library Directories in the project properties points to your Python installation's libs folder. See step 6 under Create the core C++ project.
Linker errors related to target architecture: change the C++ target's project architecture to match that of your Python installation. For example, if you're targeting x64 with the C++ project but your Python installation is x86, change the C++ project to target x86.

CLion does not pick up (complex) pre-processor definitions

EDIT: Turns out the problem was the complexity of my project. Using the simple example below works as expected, but CLion cannot make sense of the complex dependencies of the project I'm working on. Using the linked question as a workaround for now.
I'm using CLion as my C++ IDE and I've added a simple pre-processor directive as a CMake option:
cmake_minimum_required(VERSION 3.10)
project(cmake_macro_test)
set(CMAKE_CXX_STANDARD 14)
option(SIMPLE_FLAG "My simple flag." ON)
if(SIMPLE_FLAG)
add_definitions(-DSIMPLE_FLAG) # Using CMake 3.10
endif()
add_executable(cmake_macro_test main.cpp)
Then my code has conditional compilation sections of the form:
#include <iostream>
int main() {
#ifdef SIMPLE_FLAG
// Do things
std::cout << "Hello, World!" << std::endl;
#else
// Do other things
std::cout << "Goodbye, World!" << std::endl;
#endif
return 0;
}
The flag is set to on by default, so I expected Clion would pick it up from the CMakeLists.txt and highlight the relevant parts of the code.
However, Clion views the //Do things part of the code as dead, and does provide syntax highlighting or auto-complete for that section, unless I actually re-define the flag in the same file which would defeat the purpose of the CMake option.
Is this a known issue with CLion? Is there some way to guarantee that pre-processor flags get picked up by the IDE?

spdlog crash on factory methods

Yesterday I have started including spdlog into a personal project of mine to use for logging. So far I have had some problems with getting library inclusion to work but those are now solved completely.
Now everything compiles just fine, with all headers found however when I try to create loggers or simply set the pattern for logging the code crashes with a segmentation fault. More specifically no matter which function I call from the spdlog namespace for the very first time in the program causes the crash.
I have a class abstracting some parts from spdlog (based on this repo) as follows:
//Logger.hpp
#ifndef TE_LOGGER_HPP
#define TE_LOGGER_HPP
#include <spdlog/spdlog.h>
namespace te {
class Logger {
public:
static void Init();
inline static std::shared_ptr<spdlog::logger> &getCoreLogger() {
return sCoreLogger;
}
inline static std::shared_ptr<spdlog::logger> &getClientLogger() {
return sClientLogger;
}
private:
static std::shared_ptr<spdlog::logger> sCoreLogger;
static std::shared_ptr<spdlog::logger> sClientLogger;
};
}
#endif //TE_LOGGER_HPP
//Logger.cpp
#include "Logger.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>
std::shared_ptr<spdlog::logger> te::Logger::sCoreLogger;
std::shared_ptr<spdlog::logger> te::Logger::sClientLogger;
void te::Logger::Init() {
//The first of any of the following three lines cause a crash
//no matter the order, regardless of the pattern used in set_pattern
spdlog::set_pattern("%v");
sCoreLogger = spdlog::stdout_color_mt("CORE");
sClientLogger = spdlog::stdout_color_mt("CORE");
sCoreLogger->set_level(spdlog::level::trace);
sClientLogger->set_level(spdlog::level::trace);
}
From the stack traces it seems that the issue is with the formatter class in spdlog being set null for some reason somewhere within the library. I am using the latest CLion, C++14 (I am aware that spdlog is C++11, but I need features from 14 later down the line, also setting -std=c++11 doesn't solve the issue) and the latest version of spdlog as of yesterday (pulled straight from their GitHub repo) on Ubuntu 18.04.
EDIT: As per the request in the comments I have created a small project (single cpp file, include spdlog the way I do in the real project, or the same code and library setup as in the real project referenced from the main.cpp file and linked to accordingly) that aims to reproduce the issue and here are my findings:
* The issue is not present when I use spdlog directly in the executable
* The issue is present if the Logger class is moved into a shared library and linked to from there
Here is the error message I am getting:
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
And the CMakeLists.txt files I am using (I nest the library's one into the project since as of now CLion does not support "multiple projects in the same solution" like for example VS does):
#CMakeLists.txt for Library
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(TokenEngine VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES src/Application.cpp src/Application.hpp src/EntryPoint.hpp src/Logger.cpp src/Logger.hpp)
#include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs/")
add_library(TokenEngine SHARED ${SOURCE_FILES})
target_include_directories(TokenEngine PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/libs/spdlog-1.x/include")
#Expose the public API of the engine to any project that might use it
target_include_directories(TokenEngine PUBLIC include)
#CMakeLists.txt for top level project
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
add_definitions(-DTE_PLATFORM_LINUX)
project(Build CXX)
add_subdirectory(TokenEngine)
add_subdirectory(Sandbox)
You are using the same name for both loggers, when you run it you'll get:
$ ./logger
libc++abi.dylib: terminating with uncaught exception of type spdlog::spdlog_ex: logger with name 'CORE' already exists
Abort trap: 6
If you change the name of the client logger to something else it works fine:
sCoreLogger = spdlog::stdout_color_mt("CORE");
sClientLogger = spdlog::stdout_color_mt("CLIENT");
The problem is probably that spdlog’s static objects are defined twice - from inside the shared library and from client code that includes your logger header (which incldes spdlog.h).
Try to remove the include to spdlog.h from the header file and (and use forward declaration of spdlog::logger instead), and include spdlog.h only from your Logger.cpp file.
Edit:
spdlog::logger cannot be forward declared across compilation unit boundries.
The solution is to wrap the logger with some simple class defined in logger.cpp and only export it in logger.h

Code coverage error (No binaries were instrumented)

Problem:
Microsoft Visual Studio Enterprise 2015
Version 14.0.25431.01 Update 3
I'm attempting to use the code coverage function but it returns this error:
Empty results generated: No binaries were instrumented. Make sure the
tests ran, required binaries were loaded, had matching symbol files,
and were not excluded through custom settings. For more information
see http://go.microsoft.com/fwlink/?LinkID=253731
My .coverage file is full of non-sense, starting with "PCHÿ". I thought my problem looked similar to this one: Issue with Code Coverage in VS 2012, but deleting the .suo file and running Visual Studio in admnistrator didn't solve anything.
How to replicate:
1) Create new empty project "MyProject"
2) Add new file "Calculator.hpp"
#pragma once
class Calculator
{
public:
int add(int a, int b);
int sub(int a, int b);
};
3) Add new file "Calculator.cpp"
#include "Calculator.hpp"
int Calculator::add(int a, int b)
{
return a + b;
}
int Calculator::sub(int a, int b)
{
return a - b;
}
4) Add new file main.cpp
#include "Calculator.hpp"
#include <iostream>
using std::cout;
int main()
{
Calculator calc;
std::cout << calc.add(5, 11) << std::endl;
std::cout << calc.add(11, 1) << std::endl;
return 1;
}
5) Build solution. (0 errors)
6) Add new test project to solution as explained here: https://msdn.microsoft.com/en-us/library/hh419385.aspx#objectRef:
Add new Native Unit Test Project to solution "CalculatorUnitTest"
Add "main.obj" and "Calculator.obj" to Linker/Input/Additional Dependencies of "CalculatorUnitTest"
Add path to obj files to Linker/General/Additional Library Directories of "CalculatorUnitTest". (In my case: D:\JF\Programming\Tests\MyProject\MyProject\Debug)
Add the header directory of "MyProject" to VC++ Directories/Include Directories. (In my case: D:\JF\Programming\Tests\MyProject\MyProject).
7) Replace code in "unittest1.cpp" with:
#include "stdafx.h"
#include "CppUnitTest.h"
#include <Calculator.hpp>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace CalculatorUnitTest
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
Calculator calc;
Assert::AreEqual(5, calc.add(2, 3));
}
};
}
8) Build solution (0 errors, TestMethod1 appear in Test Explorer)
9) Right-click TestMethod1, "Run Selected Tests" (Test successfully passes)
10) Right-click TestMethod1, "Analyze Code Coverage for Selected Tests" (Code coverage fails).
At D:\JF\Programming\Tests\MyProject\Debug, I have both my MyProject.exe and MyProject.pdb with the CalculatorUnitTest.dll.
First of all, I am not sure if Visual Studio 2015 (C++) supports ".exe" type project for the unit test. But you are using ".obj" directly from your project. You need to place ".pdb" file in the same folder.
I created a static library project and added the unit test. Same problem on my environment.
Future here. Same problem, except my test target is a Static Library project in the same Solution.
MyLib - Code that will be tested.
MyLibTests - Project containing the tests.
Solution contains both projects.
MyLibTests has project Reference to MyLib.
<OutDir> (in .vcxproj) aka Output Directory aka $(OutDir) identical in both projects. (My value <OutDir>$(SolutionDir)$(Configuration)_$(Platform)\</OutDir>)
On your test project (MyLibTests), go
Properties
Select [Debug|platform]
Linker
Debugging
Generate Debug Info = Optimize for debugging /DEBUG
Mine was initially set for /DEBUG:FASTLINK.
Via this social MSDN post I figured it had something to do with the PDB, because MSDN (aka now "learn.microsoft.com") said this is an important step in several places, and I assume PDB are used trace calls, I assume using DbgHelp.dll.
And this sort of checklist modified from another social MSDN post:
Test project References properly set (MyLib.lib is in the same Solution as MyLibTests.dll)
Build order/dependency set/verified.
I also have Autorun on Build.
Rebuild (this should rebuild dependencies).
made sure all test were run(all test run successful)
not using optimisation (Profile Guided/Instrumentation etc).
<OutDir> aka Ouput directory should be the same, where both MyLibrary.lib/dll/exe ends up with their MyLibrary.pdb since PDB paths are linked in the exe/dll.
not using a runsettings file
Unload all other projects other than affected ones

Creating static library and linking to it with premake

I am currently trying to learn how to use premake 4 in order to apply it to the OpenGL sdk. I am currently trying to make a Visual Studio 2010 solution that constructs 2 projects, one being a static library, the other contains a single main source file, with the main method.
This project is extremely simple, and is solely for the purpose of learning premake. In the static library project, named Test, I have 2 files, Test.h and Test.cpp. Test.h contains the prototype for the method print(). print() simply prints a line to the console. Using premake, I linked the static library to the Main project, and in main.cpp I have included the Test.h file. My problem is this: in VS2010 I get this error when I attempt to build:
1>main.obj : error LNK2019: unresolved external symbol "void __cdecl print(void)" (? print##YAXXZ) referenced in function _main
1>.\Main.exe : fatal error LNK1120: 1 unresolved externals
Here is my code in the 4 files, the premake4.lua:
solution "HelloWorld"
configurations {"Debug", "Release"}
project "Main"
kind "ConsoleApp"
language "C++"
files{
"main.cpp"
}
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols" }
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize" }
links {"Test"}
project "Test"
kind "StaticLib"
language "C++"
files{
"test.h",
"test.cpp"
}
Test.cpp:
#include <iostream>
void print(){
std::cout << "HELLO" << std::endl;
}
Test.h:
void print();
Main.cpp:
#include <conio.h>
#include "test.h"
int main(){
print();
getch();
return 0;
}
If you are wondering why there is a getch() there, on my computer the console immediately closes once it reaches return 0, so I use getch() to combat that issue, which forces the window to wait until the user has pressed another key. Any advice on this issue would be wonderful, because I simply am not sure what the problem is. If it is something simple please dont castrate me on it, I have very little experience with premake and static libraries, which is why I am trying to learn them.
links {"Test"}
Lua is not Python. Whitespace is irrelevant to Lua, just like whitespace doesn't matter to C++. So your links statement only applies to the "Release" configuration. If you want it to apply to the project as a whole, it needs to go before the configuration statement, just like your kind, files, and other commands.
Premake4 works this way so that you could have certain libraries that are only used in a "Release" build (or Debug or whatever). Indeed, you can put almost any project command under a configuration. So you can have specific files that are used only in a debug build, or whatever.