Do NuGets modify the include and linking paths when added to a project?
My background is with CMake where this stuff was trivial, but I'm now at a company that builds solution files from the ground up and I'm unsure how to properly add the static OpenSSL libs to my project. I'm posting the question to make sure I don't duplicate something or otherwise mess it up.
When I add the openssl-vc141-static-x86_64 to my project, it builds the .lib files and everything, but does not modify the include or linker paths.
I can manually add the linker paths, but because the project I was given doesn't have the typical Release/Debug configurations, I can't use the $(Configuration) macro to point at the target libs - so I end of just pointing at Release. The build works though.
I see there is a .targets file, but it doesn't seem to do anything.
(update)
To be specific, I'm basically building boost's http_server_async.cpp. The linker errors I'm getting are:
Error LNK2019 unresolved external symbol _BIO_free referenced in function "public: __thiscall boost::asio::ssl::context::bio_cleanup::~bio_cleanup(void)" (??1bio_cleanup#context#ssl#asio#boost##QAE#XZ) ESOIPDataScope C:\gitrepo\ALIDB\ESOIPDataScope\DataHandler.obj
Error LNK2001 unresolved external symbol _BIO_free ESOIPDataScope C:\gitrepo\ALIDB\ESOIPDataScope\Listener.obj
... (48 more like this)
When I manually add $(SolutionDir)packages\openssl-vc141-static-x86_64.1.1.0\build\native\lib\Win32\static\Release\libcrypto.lib and
$(SolutionDir)packages\openssl-vc141-static-x86_64.1.1.0\build\native\lib\Win32\static\Release\libssl.lib to be additional dependencies the project compiles.
(/update)
Just for contrast, I added a freeglut NuGet, and noticed that gave my more configuration options (Configuration Properties → Referenced Projects), also, boost seems to have added its linker directories to my project (though I only see that in MSBuild output, not in Configuration Properties->Linker->Command Line)
Is there a proper way to add these projects that I'm missing? Or a proper way to use the targets file? Or maybe the OpenSSL static NuGet just missing something? Or maybe I should just look into vcpkg?
Do NuGets modify the include and linking paths when added to a
project?
Sure. I can tell you explicitly that the nuget imports additional properties into the project through <package_id>.targets or <package_id>.props file, instead of manually adding include path again.
This is a mechanism for nuget packaging to add additional project properties such as library path directly to the project during the installation of the nuget package. More info you can refer to this link.
The <package_id>.targets was created during the process of packing the nuget package.
In other words, this method was designed by the author of the nuget package. And in my side, the file openssl-vc141-static-x86_64.targets exists in this path:
C:\Users\Admin\source\repos\ConsoleApplication25\packages\openssl-vc141-static-x86_64.1.1.0\build\native
also, boost seems to have added its linker directories to my project
(though I only see that in MSBuild output, not in Configuration
Properties->Linker->Command Line)
l think the issue is related to the difference between <package_id>.targets and <package_id>.props. Although using <package_id>.targets does not appear on the property UI, it still works for the whole project.
In more detail
When you install the nuget package into the project, these files are automatically executed. <target_id>.props file is added at the top of the file while .targets is added at the bottom.
When initializing the xxx.vcxproj file, because <package_id> .props is at the head of the file, the property UI can capture the properties in the file, and <package_id> .targets is at the end, so the initialization cannot be captured but still In the project. For the nuget, it uses openssl-vc141-static-x86_64.targets.
In openssl-vc141-static-x86_64.targets file, you can see this:
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include\;%
(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>HAS_LIBTHRIFT;%(PreprocessorDefinitions)
</PreprocessorDefinitions>
</ClCompile>
And l have set the output log to Diagnostic and build the project and found this:
The library path has been added into AdditionalIncludeDirectories by the openssl-vc141-static-x86_64.targets file automatically. So you do not have to worry about it.
Is there a proper way to add these projects that I'm missing? Or a
proper way to use the targets file? Or maybe the OpenSSL static NuGet
just missing something? Or maybe I should just look into vcpkg?
You do not need to worry about it and do not add the include path into project property. This is superfluous and when you have finished installing this nuget package, use it in cpp files directly.
In addition,
For c++ packages installed by nuget, you don't need to add any paths to the project property.
Update 1
The issue is related to your project rather than the nuget package. Exactly because your current project does not have $(Configuration), so in openssl-vc141-static-x86_64.targets, you can see these:
<ItemDefinitionGroup Label="Win32 and vc141 and Debug" Condition="'$(Platform)' == 'Win32' And ( $(PlatformToolset.IndexOf('v141')) > -1 Or '$(PlatformToolset)' == 'WindowsKernelModeDriver8.0' Or '$(PlatformToolset)' == 'WindowsApplicationForDrivers8.0' Or '$(PlatformToolset)' == 'WindowsUserModeDriver8.0' ) And '$(Configuration)' == 'Debug'">
<Link>
<AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)lib\Win32\static\Debug\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libssl.lib;libcrypto.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /Y "$(MSBuildThisFileDirectory)\lib\Win32\dynamic\*-1_1.dll" "$(OutDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
This is the operation to import specific libssl.lib and libcrypto.Lib into the AdditionalDependencies node. But you can find out that there is a judge condition And '$(Configuration)' == 'Debug', since you do not have $(Configuration),therefore, it always returns false and these libs cannot be automatically imported into AdditionalDependencies.
As a workaround, you should add these lib path manually just as you said.
And l am sure that if you use a project which contains $(Configuration)(Debug or Release), you will not encouter this issue. And most of the C++ nuget packages can be used directly in the project which contains the Configuration node.
l am sure that if you use the $(Configuration) into your project and then reinstall this package(please clean the nuget cache before doing it), you will not face this error.
Also, your screen shot, where did you get that? I don't see anything
like that in the VS output console, or when I run msbuild on the
command line. Is there some way I might have accidentally broken the
default behaviour?
You can set MSBuild project build output verbosity to Diagnostic by Tools-->Options-->Projects and Solutions-->Build and Run.
When you build your project,the Output Window shows thw whole build process and records all the information and then you can search the key fields by the search box on the Output Window.
Related
I have a project with the following structure:
project_name/CMakeLists.txt
project_name/src
project_name/resources
...
project_name-build/configuration_name/project_name.exe
I want my application to be run in the root project directory project_name so it can directly access resources.
Does CMake provide a method to specify this property, or will I have to manually set it in each build environment I use?
I've looked around in the documentation and haven't found anything other than the possibility of setting up a post-build event to run my project from the desired directory which is less than desirable. I also found that the working directory setting for Visual Studio is saved in a per-user file (.vcxproj.user) which I don't believe CMake generates (which points to the answer being probably no).
Since CMake 3.8, there is the VS_DEBUGGER_WORKING_DIRECTORY target property, which allows you to set the debugger working directory for a target in Visual Studio.
Usage example:
set_property(TARGET MyTarget PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
As drescherjm pointed out (in his comment on the question) CMake doesn't provide a method to directly set a working directory. However, CMake does provide indirect methods of doing so.
The path I think I'll take is to use the configure_file command to fill in a template .user file.
Here is an easier solution.
Paste this at the end of your cmake:
file( WRITE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.vcxproj.user"
"<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>")
It overwrites the default vcxproj.user file for the current project and specifies $(OutDir) for the Working Directory as desired for debugging. Make sure that $PROJECT_NAME is your project name.
I am trying to compile this project: https://github.com/computationalpathologygroup/ASAP.git from source.
Pugixml is a dependency
I have built pugixml from source and set PugiXML_DIR and PUGIXML_INCLUDE_DIR And it still gives me error: "CMake Error: The following variables are used in this project, but they are set to NOTFOUND."
Things I have tried:
I am doing this on windows, using cmake 3.14 and visual studio 2017.
I have successfully built pugixml from source and included the .lib file as well
I have tried including and excluding combinations of PUGIXML_INCLUDE_DIR, PUGIXML_LIBRARY, PugiXML_DIR.
This is the error I get:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
cpp/ASAP/annotation/PUGIXML_INCLUDE_DIR
used as include directory in directory
/cpp/ASAP/annotation
cpp/ASAP/multiresolutionimageinterface/PUGIXML_INCLUDE_DIR
used as include directory in directory cpp/ASAP/multiresolutionimageinterface
Other information: setting PugiXML_DIR is mandatory, and the cmake looks for a file named "pugixml-config.cmake" in that directory. And the config cmake file is supposed to point to compiled lib file. But when it wasn't able to find, I simply copied the lib file I compiled to the location pugixml-config.cmake was pointing.
In ASAP versions before 4.04.2019 they play dirty games with extracting include directory from the IMPORTED target. annotation/CMakeLists.txt:30:
get_target_property(PUGIXML_INCLUDE_DIR pugixml INTERFACE_INCLUDE_DIRECTORIES)
In some cases this results in setting PUGIXML_INCLUDE_DIR variable to "-NOTFOUND", thus you got corresponded error message from CMake.
In commit 36d8bd75 they add FindPugiXML.cmake script, which handle find_package(PugiXML) call instead of configuration script shipped with PugiXML. In that find script they obtain include directory with find_path, which looks more natually:
find_path(PugiXML_INCLUDE_DIR pugixml.hpp)
Because in newer ASAP versions the configuration script (pugixml-config.cmake), shipped with PugiXML, is no longer used, one cannot hint about PugiXML location with PugiXML_DIR or PugiXML_ROOT. In case PugiXML is installed into non-system-default location, one may simply set PugiXML_INCLUDE_DIR variable to the PugiXML include directory.
I am confused on the right way to get an external library integrated into my own Cmake project (This external project needs to be built along with my project, it's not installed separately, so we can't use find_library, or so I think)
Let's assume we have a project structure like this (simplified for this post):
my_proj/
--CMakeLists.txt
--src/
+---CMakeLists.txt
+---my_server.cpp
That is, we have a master CMakeLists.txt that basically sits at root and invokes CMakeLists for sub directories. Obviously, in this example, because its simplified, I'm not showing all the other files/directories.
I now want to include another C++ GitHub project in my build, which happens to be this C++ bycrypt implementation: https://github.com/trusch/libbcrypt
My goal:
While building my_server.cpp via its make process, I'd like to include the header files for bcrypt and link with its library.
What I've done so far:
- I added a git module for this external library at my project root:
[submodule "third_party/bcrypt"]
path = third_party/bcrypt
url = https://github.com/trusch/libbcrypt
So now, when I checkout my project and do a submodule update, it pulls down bcrypt to ${PROJ_ROOT}/third_party
Next up, I added this to my ROOT CMakeLists.txt
# Process subdirectories
add_subdirectory(third_party/bcrypt)
add_subdirectory(src/)
Great. I know see when I invoke cmake from root, it builds bcrypt inside third_party. And then it builds my src/ directory. The reason I do this is I assume this is the best way to make sure the bcrypt library is ready before my src directory is built.
Questions:
a) Now how do I correctly get the include header path and the library location of this built library into the CMakeLists.txt file inside src/ ? Should I be hardcoding #include "../third_party/bcrypt/include/bcrypt/bcrypt.h" into my_server.cpp and -L ../third_party/libcrypt.so into src/CMakeLists.txt or is there a better way? This is what I've done today and it works, but it looks odd
I have, in src/CMakeLists.txt
set(BCRYPT_LIB,"../third_party/bcrypt/libbcrypt.so")
target_link_libraries(my app ${MY_OTHERLIBS} ${BCRYPT_LIB})
b) Is my approach of relying on sequence of add_directory correct?
Thank you.
The best approach depends on what the bcrypt CMake files are providing you, but it sounds like you want to use find_package, rather than hard-coding the paths. Check out this answer, but there are a few different configurations for find_package: MODULE and CONFIG mode.
If bcrypt builds, and one of the following files gets created for you:
FindBcrypt.cmake
bcrypt-config.cmake
BcryptConfig.cmake
that might give you an idea for which find_package configuration to use. I suggest you check out the documentation for find_package, and look closely at how the search procedure is set up to determine how CMake is searching for bcrypt.
I have a Visual Studio Project and want to write some Unit Test for it.
I tried doing that by using a "Native Unit Test Project".
The Problem is, that when I use a QString in the Test, the Test fails with following message:
Message: Failed to set up the execution context to run the test
Any suggestions how I can write Unit Test using Qt?
#include "stdafx.h"
#include "CppUnitTest.h"
#include <QtCore/QCoreApplication>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Test
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
QString a = "Test";
Assert::IsTrue(true);
}
};
}
I have tried with the above example of yours and i am able to compile the unit test. These are the following changes I've done apart from copying your code.
Check if your QT is built with 32 bit or 64 bit compiler.
You need to set the same in Solution Platforms.
You need to add include directory path and the lib file path(Qt5Cored.lib(for
debug)/Qt5Core.lib(for release)) in the Project properties.
To run the unit test you need to copy the
Qt5Cored.dll/Qt5Core.dll file in the folder where your unit test dll file is generated(After compilation).
PS:- I am using VS 2015 but this doesn't matter.
I have also ran into this issue with Qt6 with a project created using the Qt Visual Studio Tools extension for Visual Studio 2019.
QString was one of the things popping up as an error during the build process, but there was various more errors. My solution was as follows:
Gone to the Microsoft Unit Testing Framework for C++ project's Properties (right-click on solution, bottom option of the menu "Properties")
As mentioned in #sonulohani's response, I had it running in x64 by default.
Under Configuration Properties > Linker > General Additional Library Directories I added the path to my QT installation location libs folder (for me this was C:\Qt\6.1.2\msvc2019_64\lib) at the top of the list.
Under Configuration Properties > Linker > Input Additional Dependencies I added a link to all the "*.lib" files from that very same QT installation (for me, this was C:\Qt\6.1.2\msvc2019_64\lib\*.lib) AND a link to the build output .obj files for the Qt project ($(SolutionDir)<MY PROJECT NAME>\$(IntDir)*.obj where <MY PROJECT NAME> was my project name). This second part may not necessarily be needed.
Copying just the Qt6Core.dll/Qt6Cored.dll as suggested by #sonulohani did not work. It was still missing stuff. So in the properties, under Configuration Properties > Build Events > Post-Build Event Command Line I added this script to copy all the Qt6 dll files to the test project .dll output directory:
for %%f in (C:\Qt\6.1.2\msvc2019_64\bin\Qt6*.dll) do #copy /y %%f $(SolutionDir)$(Platform)\$(Configuration)\Tests\
Now at that point I had another issue, since both my test project and my actual Qt project was dumping its files into the same output directory, and the Qt project did not like having all those dlls in there and did not run anymore. So I created the $(SolutionDir)$(Platform)\$(Configuration)\Tests\ directory within the regular output directory, and also made this \Tests\ subdirectory the output directory for the test project (Configuration Properties > General Output Directory).
I'm trying (for a few days now) to build a DLL generated from C++ code with boost/python to be used by python. I am a Student from Germany and had mostly to do with Java until now (I wrote some basic OpenGL and gimp filter stuff before in C++). So pardon me in advance for bad english or C++ beginner mistakes. I mean, programming with Java really is a lot more comfortable in comparison to C++. But enough of the skirmish.
The error:
LINK : fatal error LNK1104: File "boost_python-vc110-mt-gd-1_53.lib" could not be openend
My presets:
-using MS Visual Studio 2012 (11.0)
-using boost_1_53_0
-using python2.7 (I heard 3.3 may cause some Problems)
What I did:
Installed python and added it to PATH. Then created a new empty project in VS and a class file "Test.cpp" with following content as described on the boost tutorial page:
char const* greet()
{
return "hello world";
}
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(Test)
{
using namespace boost::python
def("greet", greet);
}
Then came the new part for me, in VS Project Properties:
Configuration Properties > General > Configurationtype > Dynamic Library (.dll)
C/C++ > General > Addition Includedirectories > C:[..]\boost_1_53_0
Linker > General > Additional Library Directories > C:[..]boost_1_53_0\stage\lib
From the error I am assuming i did something wrong with Linker or Include. I also changed the Linker > General > Additional Library Directories to boost_1_53_0\libs because i wasn't sure, but the same error occured. And yes, I correctly included python. I am also not sure if i have to put something else beside python into Linker > Input for boost.
Then I build boost with bjam with no options except msvc-11.0 to be sure to have everything i need (though I read that boost/python doesn't need an extra build) and still got the same error. Can someone help me? I would love to have a step by step description of what to do. I am really despairing of this.
Btw.: I had the same error as this guy a few days before Linker error LNK1104 with 'libboost_filesystem-vc100-mt-s-1_49.lib' then stopped working on it and as I started again I got my brand new error (I can't tell you how this happened).
Since it is looking for a static library, add BOOST_PYTHON_STATIC_LIB flag, go to VS properties -> Preprocessor -> Processor definition, add BOOST_PYTHON_STATIC_LIB flag.
You need to create a "user-config.jam" file that indicates where the python headers and libs can be found by Boost.Build. You can create it in your boost_1_53_0/ directory with the following contents:
# Configure specific Python version.
using python : 2.7
: C:/Python27/python.exe
: C:/Python27/include #directory that contains pyconfig.h
: C:/Python27/libs #directory that contains python27.lib
: <toolset>msvc ;
Then from that boost_1_53_0/ directory you need to invoke b2 like this in order to build the missing library:
b2 toolset=msvc-11.0 --with-python variant=debug runtime-debugging=on link=shared --user-config=user-config.jam stage
(although I would recommend b2 toolset=msvc-11.0 --with-python --user-config=user-config.jam --build-type=complete stage so you can get in one step all the configurations that you might need in the future)
Once you have the libraries you need to add the directories to Visual Studio ( both to boost and to python).
Once you have successfully built the module you need to rename it to Test.pyd (exact name you used in BOOST_PYTHON_MODULE. If you have the python and Boost.Python libraries in your PATH or in your current directory you will be able to use the script in the tutorial:
import Test
print Test.greet()
and get the familiar "hello world".
Note that I'm very thankful for your tries but none of your answers helped. A fellow student then gave the hint for the right answer to me and some steps are really easy, others I don't understand, but it works now.
First Problem was: The new boost 1.53.0 does not work with Python27 or older. I then linked it with Python33 and had the build error removed.
But of course the build version didn't work without an error. As I tried to start my helloboost.py which imports from the .pyd built by VisualStudio and invokes the greet method, the following error occured:
ImportError: DLL load failed: The specified module could not be found.
As i checked the hello_ext.pyd with the dependency walker and wildly copy pasted around, I found out it needs the boost_python-vc110-mt-gd-1_53.dll (probably depending on what you need and built with bjam before) in the same folder. It worked then. Maybe someone can explain why nowhere was explained that I need this dll in the same folder as the pyd (or did I miss something? Is it just because I made a mistake before?)
Anyhow, I'm very glad it works now and hope it helps other people.
You probably will have worked this out by now - however:
When a .exe looks for a .dll to load no path is specified. Therefore a .dll must be in the search path for the file.
Also: I was trying to build 1.49 libs for Visual Studio 2013 - and kept getting the LNK error from my project. I don't know who suggested it on stackoverflow but someone\something gave me the idea to copy build system from a more recent boost which knows how to make .libs for more recent environments. (thank you)
I had to copy the boost build system from a 1.58 after running bootstrap in 1.58, copy b2, bjam and boost-build.jam to the earlier boost folder root to replace the same named files there. Also you will need to copy the later tools\build folder to support the build system.
Noting here in the hope it might help someone else in a similar cituation I found myself in.
See: Search Path Used by Windows to Locate a DLL