So I am trying to set the static lib projects for my main project so that I don't need to specify the folder with the .lib file. I read here how to do it.But when I set "Framework and References" -> "Link Library Dependencies" to "True" and click "Apply" it gets reset to "False". Why?
UPDATE:
As Hans Passant explained,those settings exist only for a mixed mode.But what I don't understand then,why in my case as long as "Link Library Dependencies" was set to false the libs wouldn't link automatically?Finally,btw,I was able to set it to True by removing and adding those libs back as reference and Setting Linker->General->Link Library Dependencies -YES .Now I don't need to explicitly specify lib paths in linker for these libs.But again,I am not sure that's the way to go?
Related
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.
I build my shared library:
env.SharedLibrary(target,Split(sources))
Documentation says
"On Windows systems, the SharedLibrary builder method will always build an import (.lib) library in addition to the shared (.dll) library, adding a .lib library with the same basename". That is right but I need another directory for it, so my question:
Is it possible to set another target directory for import library?
I want .dll and .lib in different directories:
bin/target.dll
lib/target.lib
It is possible to do it in VS projects but I also need a decision for Scons.
Thanks.
UPD:
We have the following structure
/project
/bin
/lib
/include
/source
SConstruct
/library
lib.cpp
SConscript
/app
SConscript
main.cpp
app depends on library.
The following scripts are very simplified.
SConstruct
g_env = Environment()
...
g_target = 'Library_' + g_arch
if g_debug: g_target += 'd'
SConscript('library/SConscript')
SConscript('app/SConscript')
library/SConscript
sources = [ .. ]
env_lib = g_env.Clone()
...
env_lib.SharedLibrary('#../lib/' + g_target,sources)
app/SConscript
sources = [ .. ]
app_env = g_env.Clone()
app_env.Append(LIBPATH = Split('#../lib'))
app_env.Append(LIBS = Split(g_target))
app_env.Program('app',sources)
If I go to app dir and run
scons -u
I get all I need:
lib/Library.dll
lib/Library.lib
source/app/app.exe
But if I want just to rebuild Library running
scons -u
from library directory - just builds me .obj files, there is no final shared library.
I have no idea why it works so, I'm not quite familiar with it. But now we need to get final libraries in different directories (.lib in lib, .dll in bin) as I mentioned above.
The standard way of doing this, would be to use the Install() method (see chap 11 "Installing files in other directories" of our UserGuide):
Install('lib','bin/target.lib')
You should set no_import_lib in your call to SharedLibrary()
env_lib.SharedLibrary('#../lib/' + g_target,sources,no_import_lib=True)
Also, are you outputing a .exp file?
Just list the name of the lib in the list of target files.
env.SharedLibrary([target, 'lib/anyname.lib'], Split(sources))
SCons will recognize the target .lib file based on its suffix (LIBSUFFIX), and it will adapt the /IMPLIB argument of the linker automatically.
How can I set with CMake in VisualStudio2010 the property "Additional Library Directories".
Example:
%(AdditionalLibraryDiretories) = "d:/librarys/wnt/i386/debug/"
configuration parameter -> linker -> general-> "Additional Library Directories"
I tried this and it doesn't work.
link_directories("d:/librarys/wnt/i386/debug/")
Turning my comments into an answer
What does link_directories() cover?
I tested it with VS2012 / CMake 3.3.0 and if you put your link_directories(...) before your add_executable(...) call it seems to work fine.
link_directories("d:/librarys/wnt/i386")
get_directory_property(_my_link_dirs LINK_DIRECTORIES)
message(STATUS "_my_link_dirs = ${_my_link_dirs}")
add_executable(...)
Everything you add with link_directories() will be appended to the directory property LINK_DIRECTORIES and assigned to whatever targets are listed afterwards.
In the upper example I get in Visual Studio "Additional Library Directories" property:
d:/librarys/wnt/i386;d:/librarys/wnt/i386/$(Configuration);%(AdditionalLibraryDirectories)
CMake does - to cover libraries depending on Config - include two variants of what you have given in link_directories(): d:/librarys/wnt/i386 and d:/librarys/wnt/i386/$(Configuration).
What if you need more flexiblity?
If your debug/release path names are not matching the VS configuration name (e.g. fooba for debug), then you can't use link_directories(). One approach would be to extend the linker flags directly:
project(...)
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /LIBPATH:\"d:/librarys/wnt/i386/fooba\"")
Then I get in the Debug config properties:
%(AdditionalLibraryDirectories);d:/librarys/wnt/i386/fooba
For the lack of flexibility of link_directories() I normally only use the target_link_libraries() command. E.g.:
target_link_libraries(MyExe debug "d:/librarys/wnt/i386/fooba/foo.lib")
would give in the Debug "Additional Dependencies" property:
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;d:\librarys\wnt\i386\fooba\foo.lib
References
CMake link_directories from library
cmake - Global linker flag setting (for all targets in directory)
I have a few dll projects in a solution (some depending on each other)
Project1 -> Properties -> Linker -> Input -> Additional Dependencies -> Project2.lib
Project1 -> Properties -> Linker -> General -> Additional Library Directories -> $(OutDir)
All is working fine.
Projects are Win7Debug Win32, Win7Debug x64..... and a Win32 project with only Debug and Release configurations.
I would like to have all dll's for Win32 placed in one folder and the x64 ones in another folder. So I added the x64 configuration for the Win32 project, and changed
Project1 -> Properties -> Linker -> General -> Output File -> $(SolutionDir)/i386/$(TargetName)/$(TargetExt)
(for Win32 - similar change for x64)
all seemed fine - and I only received dlls in the i386 folder... until I had to rebuild and got
Warning 23 warning MSB8012:
TargetPath(C:\Path\Win7Debug\Project1.dll) does not match the Linker's OutputFile
property value (C:\Path\i386\Project1.dll). This may cause your project to build
incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and
$(TargetExt) property values match the value specified in %(Link.OutputFile).
This seems serious... and I don't want to have problems with missing dependencies (though everything seems to be working fine - and not just on my machine)
I changed
Project1 -> Properties -> Configuration Properties -> General -> OutputDirectory -> $(SolutionDir)/i386
(to match the linker output) but now of course I get lib and exp files in the same folder as the dll's.
Other than using post build script, is there a way to separate the output files ?
Should I just leave the settings how I had them and disregard the warning above ?
Note: I am not trying to separate the Platform/configuration output files... That is done automagically using the default output directory.
What I need is, for each platform, to place only DLL files in one folder away from anything else. Redirecting Linker output (and leaving project output to standard) accomplishes that - I just am not sure if it is correct. Logically I should not have any build problems since I am giving linker all the info it needs...
The standard approach is to leave all these properties unchanged (inherit from parent). In this case linker will create DLL and LIB in $(Output) directory, which by default is $(SolutionDir)$(Configuration).
You just specify the name for x64 configuration, and all output files will be separated automatically.
The standard (and the easest) way to link import library is to add reference to corresponding project in Common Properties / References page. Nothing else is required.
If, for any reason, it is impossible, add $(SolutionDir)$(Configuration) to Configuration Properties / VC++ Directories / Library Directories and add library to be linked to Linker / Additional Dependencies. If there are many projects in your solution, you may create Property Sheet for the solution and specify Library Directories only once.
I require a very simple mechanism in my application, where my project is built as a shared library '.so' or '.dll', but what I want is:
ExampleAppOne.so
I get:
libExampleAppOne.so -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1 -> libExampleAppOne.so.1.0.0
libExampleAppOne.so.1.0 -> libExampleAppOne.so.1.0.0
I don't even want the 'lib' prefix. In the .pro file, all I can do is change the INSTALLS variable (that is because my third requirement IS that the library be built in a specific directory).
Also, I have a fourth, related requirement: When I ask QLibrary to load the library, I want it to specifically search for a library in a very specific path and a library that matches the EXACT name given to it. No 'lib' prefix matching, no 'version string' searching, no looking into LD_LIBRARY_PATH...
Any help is appreciated.
Regards,
rohan
add the following to you .pro file
# disables the lib prefix
CONFIG += no_plugin_name_prefix
# disable symlinks & versioning
CONFIG += plugin
Adding plugin to the CONFIG variable should disable versioning and the generation of symbolic links to the library.
I don't know of a simple way to disable the lib prefix though. You way want to dig into the provided QMake spec files to see how the default processing is implemented.