How to build boost with "Omit default library name" and Visual C++? - c++

I try to build static Boost library that will not depend on project runtime version (MT or MD). The only thing required to build such library is to add /Zl option to command line.
I edited tools/build/src/user-config.jam and specify compiler flags here:
using msvc : : : <cxxflags>/Zl ;
When I open rsp files generates by boost build system, I see /Zl flag here, for example, in regex.obj.rsp:
"libs\regex\build\..\src\regex.cpp" -Fo"bin.v2\libs\regex\build\msvc-14.1\release\address-model-64\link-static\runtime-link-static\threading-multi\regex.obj" -TP /O2 /Ob2 /W4 /GR /MT /Zc:forScope /Zc:wchar_t /favor:blend /wd4675 /EHs /Zl -c
-DBOOST_ALL_NO_LIB=1
-DNDEBUG
"-I."
So, for me it looks like the resulted library can link both /MD and /MT. However, it is not true:
libboost_regex.lib(regex.obj) : error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'
This trick (with /Zl) works for me with zlib, openssl, libcurl, libsqlite3 and many other libraries; can anyone explain why does it not work with boost? Does boost somehow override /Zl option even it exists in rsp file and in user-config.jam, or why boost libraries require the same version of runtime even /Zl option is supposed to make it runtime-independent?

Related

Windows says 64-bit executable is "Unsupported 16-Bit Application"

I have a C++ program that links Google's WebRTC library that compiles and runs successfully when I target 32-bit but doesn't work at all when I target 64-bit. After some trial and error I created the following program:
#include <media/base/adapted_video_track_source.h>
class AdaptedVideoTrackSource : rtc::AdaptedVideoTrackSource
{
public:
void AddRef() const {}
rtc::RefCountReleaseStatus Release() const { return rtc::RefCountReleaseStatus::kDroppedLastRef; }
bool is_screencast() const {return false;}
absl::optional<bool> needs_denoising() const {return false;}
bool GetStats(webrtc::VideoTrackSourceInterface::Stats* stats) {return false;}
webrtc::MediaSourceInterface::SourceState state() const {return webrtc::MediaSourceInterface::kLive;}
bool remote() const {return false;}
};
int main() {
AdaptedVideoTrackSource source;
}
This program fails with this error:
If I remove the super class the program runs fine.
How exactly do I debug a problem like this? I'm at a loss since I can't exactly debug the program. dumpbin appears to think my webrtc library is fine but says warning LNK4048: Invalid format file; ignored for my executable.
There's a lot of steps in the build process and I don't think I can put all of them here. I use CMake with ExternalProject_Add to download and build webrtc. I generate Ninja makefiles to build my code. Here are the ninja rules used to link the exe.
rule CXX_EXECUTABLE_LINKER__Test
command = cmd.exe /C "$PRE_LINK && "C:\Program Files\CMake\bin\cmake.exe" -E vs_link_exe --intdir=$OBJECT_DIR --rc=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\rc.exe --mt=C:\PROGRA~2\WI3CF2~1\10\bin\100183~1.0\x64\mt.exe --manifests $MANIFESTS -- C:\PROGRA~2\MIB055~1\2017\COMMUN~1\VC\Tools\MSVC\1416~1.270\bin\Hostx64\x64\link.exe /nologo $in /out:$TARGET_FILE /implib:$TARGET_IMPLIB /pdb:$TARGET_PDB /version:0.0 $LINK_FLAGS $LINK_PATH $LINK_LIBRARIES && $POST_BUILD"
description = Linking CXX executable $TARGET_FILE
restat = $RESTAT
build utest\Test.exe: CXX_EXECUTABLE_LINKER__Test utest\CMakeFiles\Test.dir\main.cpp.obj | <OTHER LIBARIES> || <OTHER LIBARIES>
FLAGS = /DWIN32 /D_WINDOWS /GR /EHsc /bigobj /Zi /Ob0 /Od /RTC1 -MTd
LINK_FLAGS = /machine:x64 /debug /INCREMENTAL /subsystem:console
LINK_LIBRARIES = <OTHER LIBARIES> webrtc_bundle.lib <OTHER LIBRARIES>
LINK_PATH = -LIBPATH:D:\Folder\install64\lib
OBJECT_DIR = utest\CMakeFiles\Test.dir
POST_BUILD = cd .
PRE_LINK = cd .
TARGET_COMPILE_PDB = utest\CMakeFiles\Test.dir\
TARGET_FILE = utest\Test.exe
TARGET_IMPLIB = utest\Test.lib
TARGET_PDB = utest\Test.pdb
It's private code so I renamed the executable I build and replaced the non webrtc libraries with <OTHER LIBARIES>.
This is the args.gn I use to build webrtc:
target_cpu="x64"
rtc_enable_protobuf=true
is_official_build=false
rtc_build_examples=false
rtc_include_tests=false
enable_iterator_debugging=true
is_clang=false
Also, I wrote my own BUILD.gn file to bundle webrtc with other libraries that Google's build system can build.
UPDATE
I found that I can manually link my obj files and make a perfectly good exe. Then I started going into the Ninja Makefiles generated by CMake and playing around with the linker rules. I found that if I remove /debug from the linker flags then everything works great. Of course, I want to be able to debug my debug builds.
I moved on and tried to start building my project with clang-cl and lld-link which provided a little more diagnostic output. I started getting warnings about linking different versions of the run time library. MSVC_RUNTIME_LIBRARY was correctly set and I had the /MTd flag in CMAKE_CXX_FLAGS and CMAKE_LINKER_FLAGS but by running ninja with the verbose setting I could see that my flags were being followed by /MDd which overwrote the previous runtime setting. Eventually I appended /MTd to CMAKE_CXX_FLAGS_DEBUG and CMAKE_CXX_FLAGS_RELEASE and now it's the last runtime flag in the compiler and link commands and I haven't had this problem since.

Combining PCH, PDB, and Zi leads to puzzling C2859 compile error with VS2017

I have a project that doesn't currently use precompiled headers, but I'd like to make it do so, as I've demonstrated that it leads to real compilation speed improvements in the project.
I'd also like to use /Zi, so I can capitalize on the parallel build benefits associated with /Zf, which is implied by /Zi.
I'm using the VS2017 C++ compiler, but I'm using a build system that is not Visual Studio, so answers relating to configuring VS aren't helpful.
What I'm finding is that I can set up the build to use precompiled headers just fine, or I can set it up to use /Zi just fine, but I can't seem to form a proper series of invocations to do both. When I try to do what I think is correct, I end up with error C2958 stopping the build, and I don't see what I'm doing wrong.
I've built a toy project to demonstrate what I'm seeing. The pch.hpp header looks like this:
#pragma once
#include <vector>
And we make a short mainline in main.cpp:
int main() {
std::vector<int> xs = { 1, 2, 3 };
return xs.size();
}
Note that this is the complete file contents for main.cpp: I haven't omitted anything. I am intentionally not including pch.hpp here, because we are going to force inject it with /Fi later. The real project doesn't have include lines for a precompiled header in all the right places, and there would be thousands of files to update to do so. Note that the approach using /Fi does appear to work in the command lines below, and has the advantage that a forceincludes based mechanism can work with GCC style precompiled headers as well.
If we build things without /Zi, everything goes fine:
cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch
pch.hpp
cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch
main.cpp
We find the files we would expect to find under the build directory:
main.obj pch.obj pch.pch
However, if we try to use /Fi and /Fd to generate a per-file .pdb and control its name, it doesn't work at all:
We can compile the precompiled header that way OK:
cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch /Zi /Fdbuild\pch.pch.pdb
And things look OK in the build directory so far:
pch.obj pch.pch pch.pch.pdb
But when we try to build the object file for main, it all falls apart:
cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch /Zi /Fdbuild\main.obj.pdb
main.cpp
main.cpp: error C2859: Z:\data\acm\src\example\build\main.obj.pdb is not the pdb file that was used when this precompiled header was created, recreate the precompiled header.
This is a very puzzling error, because the error message suggests that main.obj.pdb is being treated as an input somehow, but in fact it is intended to be the name of the .pdb file generated as output, per the value of the /Fd flag for the build of main.obj.
Googling hasn't resulted in much useful guidance, with a lot of hints about reconfiguring VS settings, which isn't really useful in the case of a build driven by something else.
I've also verified that my trickery with the /Fi of pch.hpp isn't the issue. If I update main.cpp to #include pch.hpp and remove the /Fipch.hpp from the compile line for main.obj, the same C2859 error still occurs.
I realize there are a lot of flags to get right when using precompiled headers, among them the /Yc and /Yu and /Fp flags, but I think I've got those handled correctly.
Does anyone see where I've got things wrong?
Edit 1 - Demonstrating that /Fd can name different PDB files
In response to the comment below, it doesn't actually appear to be the case that all targets must share the /Fd argument. Here is an example without the use of precompiled headers that demonstrates that:
Here, I've needed to add common.cpp and create a main1.cpp and main2.cpp which both link it:
The common.hpp header looks like:
#pragma once
int common(int arg);
With a trivial implementation in common.cpp:
#include "common.hpp"
int common(int arg) {
return arg + 42;
}
Then introduce two different mainlines:
main1.cpp:
#include "common.hpp"
int main() {
std::vector<int> xs = { 1, 2, 3 };
return common(xs.size());
}
And main2.cpp:
#include "common.hpp"
int main() {
std::vector<int> xs = { 1, 2, 3, 4};
return common(xs.size());
}
Then compile all three object files. Note that we still have the /Fipch.hpp here to make the includes work right, but we aren't using any of the actual PCH machinery:
cl /Fobuild\common.obj /c common.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\common.obj.pdb
cl /Fobuild\main1.obj /c main1.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main1.obj.pdb
cl /Fobuild\main2.obj /c main2.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main2.obj.pdb
And we find what we would expect in the build directory:
common.obj common.obj.pdb main1.obj main1.obj.pdb main2.obj main2.obj.pdb
Then we can go ahead and link:
link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main1.exe /PDB:build\main1.pdb build\common.obj build\main1.obj
link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main2.exe /PDB:build\main2.pdb build\common.obj build\main2.obj
And we find that we get both executables and PDB files for those executables in the build directory:
common.obj main1.exe main1.obj.pdb main2.exe main2.obj.pdb
common.obj.pdb main1.obj main1.pdb main2.obj main2.pdb
From the Microsoft documentation for C2859 and creating precompiled headers, the database used to store the debug information must be shared among all source modules using the precompiled header. Having all that shared debug information stored in one database greatly reduces the size of the object files and speeds up linking since the linker does not have to deal with all that repetition.
If you want all your compiled files to have their own copies of the debug information, use the /Z7 option instead.

LINK1104 cannot open boost static library using visual studio 2008 command prompt

I'm trying to compile a cpp file which uses static boost libraries. I'm using the visual studio 2008 command prompt as I have not set up a VS project file.
The command I'm using is (run from the folder containing my source code):
cl /EHsc /I "C:\Program Files\boost\boost_1_53_0" Client.cpp
The error is:
LINK: fatal error LNK1104: cannot open file 'libboost_system-vc90-mt-s-1_53.lib'
However, the file 'libboost_system-vc90-mt-s-1_53.lib' can be found in "C:\Program Files\boost\boost_1_53_0\stage\lib" so my understanding is that I've installed boost properly and I'm just failing to link to it?
I've tried including it directly using
cl /EHsc /I"C:\Program Files\boost\boost_1_53_0" /I "C:\Program Files\boost\boost_1_53_0\stage\lib\" Client.cpp
which gives the same error.
I've also tried linking to it directly using /link as follows:
cl /EHsc /I"C:\Program Files\boost\boost_1_53_0" /link "C:\Program Files\boost\boost_1_53_0\stage\lib\libboost_system-vc90-mt-s-1_53.lib" Client.cpp
Which returns a different error:
cl : Command line error D8003 : missing source filename
I seem to be calling the compiler flags wrong? But I can't see where/how.
There is a similar question here,but the solution involves issues with how visual studio/ the project file is set up. Since I don't have a project file, is there an easy solution for the above that I can't see or would I need to set up a project?
Thanks for any help in advance!
The linker needs to be told where the library file is located. You were very close with the last command line, but the file name needs to precede the /link option. This should work:
cl /EHsc /I"C:\Program Files\boost\boost_1_53_0" Client.cpp /link "C:\Program Files\boost\boost_1_53_0\stage\lib\libboost_system-vc90-mt-s-1_53.lib"
Also, when linking to multiple libraries in the same directory, it is more concise to use the LIBPATH option to tell the linker where to look for .lib files.
cl /EHsc /I"C:\Program Files\boost\boost_1_53_0" Client.cpp /link "libboost_system-vc90-mt-s-1_53.lib" /LIBPATH:"C:\Program Files\boost\boost_1_53_0\stage\lib\"

Which compilation options should I use to link with Boost using cl.exe?

I have a program which I would like compile using cl.exe on the command-line. This program depends on some boost libraries which I fail to link to.
The error I'm getting is:
cl /Fosamples\proxy\proxy.obj /c samples\proxy\proxy.cpp /TP /O2 /EHsc
/DBOOST_ALL_NO_LIB /DBOOST_THREAD_USE_LIB /DBOOST_SYSTEM_USE_LIB
/DBOOST_USE_WINDOWS_H /DTAP_ID=\"tap0901\" /D_WIN32_WINNT=0x0501 /MD /nologo
/Isamples\proxy /Iinclude proxy.cpp
link /nologo /MD /OUT:samples\proxy\proxy.exe /LIBPATH:samples\proxy
/LIBPATH:lib asiotap.lib libboost_system-vc100-mt-1_47.lib
libboost_thread-vc100-mt-1_47.lib ws2_32.lib gdi32.lib iphlpapi.lib
advapi32.lib samples\proxy\proxy.obj
LINK : warning LNK4044: unrecognized option '/MD'; ignored
asiotap.lib(bootp_builder.obj) : error LNK2001: unresolved external
symbol "class boost::system::error_category const & __cdecl
boost::system::system_category(void)"
(?system_category#system#boost##YAAEBVerror_category#12#XZ)
I compiled Boost, using the following command-line, from the x64 MSVC command prompt:
.\b2.exe install toolset=msvc --prefix=C:\Boost-VC-x64
If I look inside libboost_system-vc100-mt-1_47.lib I can see that:
?system_category#system#boost##YAABVerror_category#12#XZ
Is exported. But If you look closely it differs a bit from the one in my compilation errors:
?system_category#system#boost##YAAEBVerror_category#12#XZ // The symbol I miss
?system_category#system#boost##YAABVerror_category#12#XZ // The exported symbol
I guess I should either change Boost or my compilation options but fail to figure what to change exactly. Any clue ?
Thank you very much.
After some investigations, I realized that I compiled Boost for a x86 platform where I was linking with a x64 binary.
I thought that compiling Boost inside a Visual Studio x64 command prompt was enough but you actually have to specify:
.\b2.exe install toolset=msvc address-model=64 --prefix=C:\Boost-VC-x64
To make it work.

How to link against a static library which uses static libraries itself using scons and Visual C++?

My SConstruct file looks something like this:
jnglLibs = Split("freetype png ogg vorbisfile") # left out a few
env.Library(target="jngl", source=source_files, LIBS=jnglLibs)
env.Program("test.cpp", LIBS=Split("jngl") + jnglLibs)
The static library links fine but the program fails with unresolved external symbols from the libraries in jnglLibs.
lib /nologo /OUT:jngl.lib finally.obj freetype.obj main.obj opengl.obj sprite.ob
j tess.obj texture.obj window.obj windowptr.obj callbacks.obj ConvertUTF.obj aud
io.obj win32\message.obj win32\time.obj win32\window.obj
cl /Fotest.obj /c test.cpp /TP /nologo /EHsc /MD -O2 -DNDEBUG /I.
test.cpp
link /OUT:test.exe /LIBPATH:. /LIBPATH:lib jngl.lib freetype.lib png.lib opengl3
2.lib glu32.lib user32.lib shell32.lib gdi32.lib z.lib jpeg.lib dl.lib openal32.
lib alut.lib ogg.lib vorbisfile.lib test.obj
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
jngl.lib(freetype.obj) : error LNK2019: unresolved external symbol FT_Done_FreeT
ype referenced in function "public: __cdecl jngl::Font::~Font(void)" (??1Font#jn
gl##QEAA#XZ)
... and so on
Why doesn't it find the symbol FT_Done_FreeType which is in freetype.lib? It works perfectly with GCC.
There are a lot of quirks with static linking on Windows.. I've had one or two similar problems to this but mostly my problem was once the 'static' libs were compiled they still depended on the .dll's being there. Anyway, I've been feeling your pain for a while now but got through it for my purposes... here's one page that really helped me.
http://xmlsoft.org/XSLT/tutorial2/libxslt_pipes.html#windows-build
It doesn't have to do with those particular libraries you listed but it might give you some clues. One thing is figuring out which C-runtime library each of those .libs (or '_a.libs,' which you might want to look into) were compiled against and make sure they are all the same when you statically link. So since you're using /MD, make sure all those libs were also compiled with /MD and not /MT. That COULD be a reason it isn't finding that freetype symbol, but it's just one guess. Good luck!