Dependent project cannot see headers from a library in refferences in Visual Studio - c++

I am learning how to make a static library. I started with windows and Visual Studio.
The directory structure looks like this:
- MyLibraryProject
- include
- MyLibraryProject
- MyLibraryHeader.h
- src
- MyLibrarySource.cpp
- build
- MyLibraryProject.vcxproj
- MyDependentProject
- main.cpp
- MyDependentProject.vcxproj
MyLibraryProject.vcxproj has the following settings:
Setting
Value
Configuration type
Static library (.lib)
Additional Include Directories
$(MSBuildThisFileDirectory)../include/MyLibraryProject
MyDependentProject.vcxproj has no special settings, except I added MyLibraryProject onto refferences, the image features actual names I used:
If I use relative paths in main.cpp, I can build the project - the static linking works just fine and it runs:
#include "../MyLibraryProject/include/MyLibraryProject/MyLibraryHeader.h"
However, I want to include the headers like this:
// fatal error C1083: Cannot open include file: 'MyLibraryProject/MyLibraryHeader.h': No such file or directory
#include <MyLibraryProject/MyLibraryHeader.h>
And that just does not work. I also tried to use property sheet but couldn't get that to work either. I've been searching the internet, but generally found claims that if you add a reference, both headers and static libs will work.
Here's the full repository, if you're willing to take a look. Or ask in the comments if there's information missing.

Project references do not provide the dependent project with any information about headers. The most flexible way to do this instead (in Visual Studio) are property sheets. I created a file MyLibraryProject/build/MyLibraryProjectDependency.props:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />
</Project>
And I added it to MyDependentProject.vcxproj in Property explorer in Visual Studio. This solved the issues and headers are now seen on the path I want them.

Related

Debugging CMake Visual Studio project with PATH environment set by VS_DEBUGGER_ENVIRONMENT

I've created a CMake project using visual studio 2019. It has one executable target, which links to some shared libraries (DLL). I cannot directly set the system environment variable PATH because the DLL path is determined by find_package. Therefore, set VS_DEBUGGER_ENVIRONMENT target property is my choice to debug that executable target.
However, the VS_DEBUGGER_ENVIRONMENT property is not working when I directly open the CMake project and debug that target. I've checked the .vsproj it has the correct LocalDebuggerEnvironment tag generated.
But if I run cmake -G "Visual Studio 16 2019" ../ and open the generated visual studio solution and then debug the subproject from there, everything turns out to be ok.
I think maybe the visual studio doesn't support LocalDebuggerEnvironment when opening project as a CMake project. Or perhaps I didn't debug it the right way. Is there anything else I can do to change the visual studio debug runtime PATH environment using CMake?
Any suggestion would be greatly appreciated!
This is just to share what I finally ended up with after some painful hours of digging through the web.
First, a variable to store the required debugging paths is needed (example):
list(APPEND VS_DEBUGGING_PATH "%PATH%")
list(APPEND VS_DEBUGGING_PATH "${PostgreSQL_ROOT}/bin")
The next step is to create a ${CMAKE_PROJECT_NAME}.vcxproj.user template file for C/C++ and in my case also a ${CMAKE_PROJECT_NAME}.vfproj.user template for FORTRAN (just for the record):
file(
WRITE "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vcxproj.user"
"<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">
<PropertyGroup Condition=\"'\$(Configuration)'=='Release'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='MinSizeRel'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='RelWithDebInfo'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
<PropertyGroup Condition=\"'\$(Configuration)'=='Debug'\">
<LocalDebuggerEnvironment>PATH=#VS_DEBUGGING_PATH#</LocalDebuggerEnvironment>
</PropertyGroup>
</Project>"
)
file(
WRITE "${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vfproj.user"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<VisualStudioUserFile>
<Configurations>
<Configuration Name=\"Release|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"MinSizeRel|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"RelWithDebInfo|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
<Configuration Name=\"Debug|x64\" Environment=\"PATH=#VS_DEBUGGING_PATH#\"/>
</Configurations>
</VisualStudioUserFile>"
)
As you might see, both template files are just dumped into the root of ${CMAKE_BINARY_DIR} in this case. The base name ${CMAKE_PROJECT_NAME} is also arbitrary.
Those templates can then finally be "configured" (copied) into each target folder of your setup. Either for C/C++
configure_file(
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vcxproj.user"
"${CMAKE_CURRENT_BINARY_DIR}/${target_name}.vcxproj.user"
#ONLY
)
or FORTRAN
configure_file(
"${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.vfproj.user"
"${CMAKE_CURRENT_BINARY_DIR}/${target_name}.vfproj.$ENV{USERNAME}.user"
#ONLY
)
or even both if necessary. The variable ${target_name} needs to replaced with your target name of course. :-)
This should suffice. It is however important to close VS 2019 before (re-)configuring/(re-)generating with CMake. Otherwise VS 2019 might simply overwrite those files for each target.
I strongly hope this is helpful.
Please let me know if you need more details.
Here is the result for C/C++ targets and here for FORTRAN targets

How to set .vcxproj to let MSBuild compile a dll

Above All
To save your time from reading a lot, Thanks to CristiFati and here is the answer:
If you use "Library" in "ConfigurationType" like me, you'll get an .obj file instead of .dll.
The right keyword is "DynamicLibrary" instead of "Library". That is:
<ConfigurationType>DynamicLibrary</ConfigurationType>
Then you'll have the .dll you want.
[supplement] From CMake Documents, thanks to Botje's guiding, it appears that a "Library" is actually like a sub-directory under the root project. Thus it's different with how dll work.
Short Story:
I need to compile a dll with MSbuild, without any IDE.
I followed instruction on Microsoft Doc to create app build project.
No webpage indicates how to create dll build project is found yet. Thus I edit .vcxproj according to similar google info.
BUILD SUCCESS!
But the result only contain a .obj file. No dll in sight.
Need help about how to modify a .vcxproj to build a dll.
Detailed Story:
I need to compile a dll.
My company didn't buy any commercial license thus I cannot use any IDE for this.
However MSBuild is safe to use.
I'm following this page to create a C++ project which could be compiled with MSBuild only.
https://learn.microsoft.com/en-us/cpp/build/walkthrough-using-msbuild-to-create-a-visual-cpp-project?view=vs-2017
You don't need actually read that page because I'll paste the project file below.
First, Following that page, I got this application type project file
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemGroup>
<ClCompile Include="helloworld.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="helloworld.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>
I tested the build. And got my .exe file successfully. And my helloworld.exe printed "HelloWorld" as predicted. Then...
Second, Following this page:
https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=vs-2017
I'm sure the header and cpp file is good to go
#pragma once
#ifdef HELLOWORLD_EXPORTS
#define HELLOWORLD_API __declspec(dllexport)
#else
#define HELLOWORLD_API __declspec(dllimport)
#endif
extern "C" HELLOWORLD_API void helloworld();
Third, Switch this project from application mode to library mode...
Actually I'm not sure how to do this. So I googled some info and try to do what they did.
I change the Debug mode to Release mode.
Then change the Application output to Library.
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.default.props" />
<PropertyGroup>
<ConfigurationType>Library</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ItemGroup>
<ClCompile Include="helloworld.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="helloworld.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>
Finally, I let msbuild do its work:
msbuild helloworld.vcxproj /p:configuration=Release
And the build is success!
But when I head to Release folder under my root directory, I find only a "helloworld.obj" file and a "vc141.pdb" along a folder names "helloworld.tlog".
Well this is not right. I think the right result will be a "helloworld.dll" in here.
So, that should be my .vcxproj file's problem I guess.
So, could anybody kindly give a guide for creating a dll project from scratch?
Thanks!
Although using the IDE is prohibited by licensing purposes, listing [MS.Docs]: Walkthrough: Create and use your own Dynamic Link Library (C++) anyway.
The keypoint is:
3. From the filtered list of project types, select Dynamic-link Library (DLL), and then choose Next.
Behind the scenes, that maps to: [MS.Docs]: ConfigurationTypes Enum:
Fields
typeApplication             1      Application (.exe)
typeDynamicLibrary      2      Dynamic Library (.dll)
typeGeneric                 10      Makefile, displays makefile toolset (NMake)
typeStaticLibrary           4      Static Library (.dll)
typeUnknown                0      Utility
Translated to .vcxproj structure, the ConfigurationType node:
<ConfigurationType>Application</ConfigurationType>
should be converted to:
<ConfigurationType>DynamicLibrary</ConfigurationType>
But, as (#Botje's) comments rightly pointed out, you should move towards free build tools (there are a number of alternatives, and CMake seems to be the best one).

Custom Build Files changes do not trigger project rebuild in VS 2017

In my C++ VS project I added a custom target to compile shader files and set it as a initial target. This is the project xml
<Project InitialTargets="CompileShaders" DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
..... Normal Default VS C++ content here ......
<ItemGroup>
<GLSLShader Include="SPIR-V\canvas2D.vert" />
<GLSLShader Include="SPIR-V\canvas2D.frag" />
</ItemGroup>
<Target Name="CompileShaders" Inputs="#(GLSLShader)" Outputs="SPIR-V\shaders_bytecode.h" >
<PropertyGroup>
<OriginalFileName>%(GLSLShader.Filename)%(GLSLShader.Extension)</OriginalFileName>
</PropertyGroup>
<Message Text="Start Compiling GSLANG #(GLSLShader) " />
<Message Condition="'$(VULKAN_SDK)'==''" Text="Error, cant find environment variable VULKAN_SDK, Make sure that the Lunar Vulkan SDK is installed" />
<Message Condition="'$(VULKAN_SDK)'!=''" Text="$(VULKAN_SDK)\Bin\glslangValidator.exe %(GLSLShader.Filename)%(GLSLShader.Extension) -V --vn $([System.String]::Copy('%(GLSLShader.Filename)%(GLSLShader.Extension)').Replace('.','_')) -o %(GLSLShader.Filename)%(GLSLShader.Extension).h" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="$(VULKAN_SDK)\Bin\glslangValidator.exe %(GLSLShader.Filename)%(GLSLShader.Extension) -V --vn $([System.String]::Copy('%(GLSLShader.Filename)%(GLSLShader.Extension)').Replace('.','_')) -o %(GLSLShader.Filename)%(GLSLShader.Extension).h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="del shaders_bytecode.h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="type %(GLSLShader.Filename)%(GLSLShader.Extension).h >> shaders_bytecode.h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
<Exec Condition="'$(VULKAN_SDK)'!=''" Command="del %(GLSLShader.Filename)%(GLSLShader.Extension).h" WorkingDirectory="$(ProjectDir)\SPIR-V" />
</Target>
</Project>
if I change any .cpp .h file and build the solution, the shaders are compiled together with the rest of the project, but if I change only the shader files (i.e SPIR-V\canvas2D.vert) the project is not built. VS says that the project is up to date.
Now the strange thing, If I run the project using msbuild on the terminal ouside VS, the shader files changes are enough to trigger the rebuild. Go figure....!!!
It looks like something related to how VS build projects. It is outside the msbuild.
Aha!! Found it in this article. It turns out visual studio bypass msbuild and uses some other criteria to verify if a project is up to date or not. If the criteria fails it then runs the msbuild on that project.
To override the visual studio behavior set the property DisableFastUpToDateCheck as true in the Globals property group of your project's xml:
<PropertyGroup Label="Globals">
<!-- Other Global Property Settings -->
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
And it is done... I wonder if there is a away to tell Visual Studio FastUpToDateCheck Mechanism to also pay attention to the custom build files ????? The solution above will suffice for now.

Include path relative to props file in visual studio

I'm trying to create property file with include path to use in all my c++ project.
Here is repository structure.
/
/Libs
/Libs2
A.h
B.h
/Sln1
Sln1.sln
Proj1.vcxproj
Sln2.sln
Proj2.vcxproj
Props.props
I want use property file (Props.props) to add the following include path to both projects ( C:\\Libs;C:\\Libs\Libs2).
Currently I have macro in my property file:
Name Value
ProjRoot C:\<path to rep root>
And I use it in include string: $(ProjRoot)\Libs;$(ProjRoot)\Libs\Libs2
The problem with this solution is hardcoded absolute path in macro value. If my repository will be cloned on another drive I will have to change it manually.
Can I use path relative to property file in macro value?
I.e.:
Name Value
ProjRoot ./
Where ./ will resolve to path of Props.props file in all projects which will use this property file.
I cannot use $(SolutionDir) and $(ProjectDir) because there are may solutions and projects in different nesting level so path relative to them would not work.
Thank you.
Do do this one should manually edit props file and include the following:
<PropSheetPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))</PropSheetPath>
This will create property PropSheetPath with property file folder.
Found the answer here:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/2817cae7-3a71-4701-839a-9bf47af7c498/property-sheets-macro-to-reference-location-of-property-sheet?forum=vcgeneral
Just to improve previous answer... Here how it looks as a full example (I'm using a bunch of small property sheets to add third party libraries in a modular way). This is an example for adding paths to include folders for C++ compiler and library folders for linker to add CEGUI library into project (debug version, I use separate prop sheet for Release).
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<PropSheetPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)'))</PropSheetPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Language)'=='C++'">
<CAExcludePath>$(PropsheetPath)..\..\install\windows\Debug\include\cegui-0;$(CAExcludePath)</CAExcludePath>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>CEGUI_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(PropsheetPath)..\..\install\windows\Debug\include\cegui-0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(PropsheetPath)..\..\install\windows\Debug\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>DbgHelp.lib;CEGUIBase-0_Static_d.lib;CEGUICommonDialogs-0_Static_d.lib;CEGUICoreWindowRendererSet_Static_d.lib;CEGUIExpatParser_Static_d.lib;CEGUIOpenGLRenderer-0_Static_d.lib;CEGUITGAImageCodec_Static_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

What is the $(PackageConfiguration) variable in a Visual Studio project?

I ran into a linker error (Couldn't open sqlite3.lib) when making a WinRT application. The funny thing is, it only happens in a new configuration that I made (Master, as opposed to Debug or Release). I cloned the new configuration from Release, so it should be identical except for a few preprocessor defines. I found the following entry as a default in my "Library Directories" section under "VC++ Directories"
$(FrameworkSDKRoot)..\v8.1\ExtensionSDKs\SQLite.WinRT81\3.8.0.2\DesignTime\$(PackageConfiguration)\$(PlatformTarget)
However, I can't find any information on what the PackageConfiguration variable actually expands to. I guessed it might be Debug / Release but the folders at that location on the file system are Debug and Retail. If I add another entry with "Retail" instead of $PackageConfiguration then I can build the program properly, but it seems strange. Does anyone know how this variable is defined?
This value comes from the SQLite.WinRT81.props file located in the SQLite extension SDK which is usually installed here:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1\ExtensionSDKs\SQLite.WinRT81\3.8.2\DesignTime\CommonConfiguration\neutral
On my machine the contents look like this:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PackageConfiguration Condition="'$(Configuration)' == ''">Debug</PackageConfiguration>
<PackageConfiguration Condition="'$(Configuration)' == 'Debug'">Debug</PackageConfiguration>
<PackageConfiguration Condition="'$(Configuration)' == 'Release'">Retail</PackageConfiguration>
</PropertyGroup>
<PropertyGroup>
<IncludePath>$(FrameworkSDKRoot)\..\v8.1\ExtensionSDKs\SQLite.WinRT81\3.8.2\DesignTime\CommonConfiguration\Neutral;$(IncludePath)</IncludePath>
<LibraryPath>$(FrameworkSDKRoot)\..\v8.1\ExtensionSDKs\SQLite.WinRT81\3.8.2\DesignTime\$(PackageConfiguration)\$(PlatformTarget);$(LibraryPath)</LibraryPath>
<PropertySheetDisplayName>SQLite.WinRT81, 3.8.2</PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>sqlite3.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>