Visual Studio Incremental Linking Full Relinks With Templates - c++

I have an issue with incremental linking in that when I change some code it sometimes does a full link. I have narrowed the code down to a specific piece and was wondering if anyone knows why.
I am using Visual Studio 2012 (it exhibits the same behavior in 2015).
I have created a blank solution with 2 projects in it (a lib and an exe). I have setup incremental linking to work properly (importing library outputs as well).
The exe simply has main call into 'UpdateFrame' which is listed below.
This is all the code from the library project itself.
struct TypeId
{
unsigned char myTypeId;
// Comment out this line and it links incrementally
TypeId() : myTypeId(0) {}
};
template<class Type>
struct TypeRegistrationHelper
{
static TypeId ourTypeId;
};
template<class Type> TypeId TypeRegistrationHelper<Type>::ourTypeId;
// Uncomment this line and it links incrementally
//template struct TypeRegistrationHelper<float>;
void UpdateFrame()
{
// Commenting/uncommenting this line causes a full link to happen
// unless you have changed 1 of the 2 lines listed above. Then it links
// incrementally as expected when changing this line.
TypeRegistrationHelper<float>::ourTypeId;
}
The problem comes up that if I comment out the line in UpdateFrame, it causes a full link to happen (unless I have modified one of the two lines that are commented in code -- then everything works fine)
I've enabled verbose output for incremental linking and this is the reason it lists as performing a full relink:
LINK : directives changed; performing full link
This is the MSDN page regarding this particular error (note it says its for VC 6.0)
Linker Tools Warning LNK6019
And this is the only information it contains
A directive was added or deleted since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.
Here is my main function (in the application project obviously)
#include "Updater.h"
int main()
{
UpdateFrame();
return 0;
}

Related

Random error in exe_common.inl in Debug build

I am using VS 2022 Community Edition (v17.3.3) to build wxWidgets application (v3.2.0) using C++ (v14.3 - Features from Latest C++). The windows SDK is using the latest installed (10.0.22621). The project is also using C++ modules.
The Debug build succeeds but when I run the project's exe file at random it throws the exception (Access violation reading 0xFFFFFF (ucrtbased.dll)) in exe_common.inl at the following line:
__scrt_current_native_startup_state = __scrt_native_startup_state::initialized;
After a few more compilations (by just making minor changes to trigger a compilation) it succeeds and the exe runs correctly.
I wonder if there is any settings that might be causing this random error. Btw, I am using Win11 but same thing happens on Win10 as well.
Thanks in advance.
EDIT 1:
The project is using boost libraries and at startup boost/json (boost/json is used in other parts of the project as well). Debugger shows that after the following line the above error happens:
static allocator_arg_t allocator_arg = BOOST_CONTAINER_DOC1ST(unspecified, *std_allocator_arg_holder<>::dummy);
There were a few things needed attention:
Discontinued use of wxSQLite (the library was not maintained for over a decade),
The main frame was a singleton data structure, not anymore, and not deriving from wxMDIFrame anymore.
All unnecessary (a chain of them) #include removed.
Inclusion of <boost/json.hpp> in a few files were removed and now using #include <boost/json/src.hpp> only in one .cpp file. However, the project still uses inclusion of <boost/json/value.hpp> in multiple .h files.
All uninitialized pointer variables and others were initialized.
#1 and #4 were especially pointed by the debugger. It has now been more than a few days and haven't had the problem since then.

Debugging into MFC header code does not work with Visual Studio 2019

TL;DR: Debuigging into MFC (CString) header code does not work on both my machines and as far as I can tell this is due to the peculiar way these headers are compiled.
Stepping through MFC header code when entered via disassembly works, but setting brealpoints does not work.
I'm looking for a workaround or at least acknowledgement of my analysis.
System:
Visual Studio 2019 Professional 16.9.6
Windows 10 / 1809 Enterprise LTSC
Setup: (I do apologize for this being rather long.)
Create a Visual Studio 2019 Example MFC Application Project (SDI App)
Make sure Enable Just My Codeis off under Options -> Debugging -> General.
Set the build configuration to Debug/x64 (does not make a difference, but let's all stay on the same page)
Navigate to MFCApplication1.cpp -> CMFCApplication1App::InitInstance()
Insert a CString init like this:
...
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance(); // please put breakpoint 1 here
// Add this line and set breakpoints
CString this_is_text(L"Debugging into CString Header does not work!"); // breakpoint 2 here
Now, you can start the program under the debugger, and you should stop at the first breakpoint:
Now, make sure all symbols are loaded, easiest done via the Call Stack:
Just select all lines in the call stack window and hit Load Symbols in the context menu. Afterwards the call stack should look roughly like this:
> MFCApplication1.exe!CMFCApplication1App::InitInstance() Line 75 C++
mfc140ud.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 37 C++
MFCApplication1.exe!wWinMain(HINSTANCE__ * hInstance=0x00007ff7b5070000, ...) Line 26 C++
MFCApplication1.exe!invoke_main() Line 123 C++
MFCApplication1.exe!__scrt_common_main_seh() Line 288 C++
MFCApplication1.exe!__scrt_common_main() Line 331 C++
MFCApplication1.exe!wWinMainCRTStartup(void * __formal=0x000000c2b7084000) Line 17 C++
kernel32.dll!BaseThreadInitThunk() Unknown
ntdll.dll!RtlUserThreadStart() Unknown
Now, you can try stepping-into (possibly F11) the CWinAppEx::InitInstance() function, which should work without a problem, landing you in mfc140ud.dll!CWinApp::InitInstance() Line 394 - this is OK.
Step out again, and then then try to step-into the CString ctor:
This DOES NOT work on my machine(s)!
What I can do however, is (from the point above) switch to disassembly view, step into the calls there and get into the header code this way:
I can then successfully step through (but never into) the MFC header code. Trying to set a breakpoint will result in the error:
The breakpoint will not currently be hit. No executable code of the debugger's code type is associated with this line.
Possible causes include ...
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h
And this is where I'm at.
Analysis:
What we can see from the MFC code is that we can step into "regular" cpp code, but as soon as we try to step into (or set breakpoint) code that is inside this CStringt.h it breaks.
Peculiar here: This is template header code, and still the executed code (as shown by the disassembly) is not in the user module but in the mfc###.dll! I think they do some clever tricks with the preprocessor (see defined(_MFC_DLL_BLD) and somesuch) which enables this multi use of the header file, and maybe, possibly this is also what breaks the debugger.
Question:
Is this a known problem, does this happen with all VS2019 installs, is there something peculiar to my setup?
Maybe fixed in a newer VS version?
Iff this is actually broken, what would be a useable workaround, other than constantly switching to disassembly view when into the MFC headers.
The most interesting answer here would actually be as to WHY this breaks - where does the debugger get confused? Is this a general problem with re-define-ing code when debugging library code?
The source shipped with MSVC does not match.
I think this happen, as DLLs got updated with Windows Update or a new vcredist, but Visual Studio includes are not updated. If you build with /MT or /MTd and link MFC statically, the problem does not persist.
Probably this can be reported to http://developercommunity.visualstudio.com if you care.
Workaround 1
Do steps described by #selbie:
Set a breakpoint on the line of code I want to step into.
When
the breakpoint is reached, right click in the editor window and select
"Go To Disassemly".
In disassembly mode, step over until you get to
a call statement. [...] You
can flip out of disassembly mode by right-clicking again and selecting
"go to source code".
(skipped the part not relevant to this issue)
Then pick up the location of the header manually, the debugger will tell that it does not match. The difference seem to be insignificant though, so the header is usable.
Workaround 2
Link MFC statically, compile with /MT or /MTd
Workaround 3
ATL has a similar CString that does not suffer from the issue:
#include <atlbase.h>
#include <atlstr.h>
int main() {
ATL::CString this_is_text("Debugging into CString header works");
}
Analysis went sideways at some point, but we finally found one part of the problem here:
The Require source files to exactly match the original version option:
was the problem, but in a very peculiar way:
When you do NOT require source files to match (that is, disable this default option), then the erroneous behavior of the OP occurs: The debugger can no longer match the symbols to the cstringt.h file.
Unfortunately, I had this disabled on both machines. Pulling in a third machine showed that we could set breakpoints (though F11 still does not work) and by comparing the xml export of the VS settings we found that this was different.
So, long story short: For us, to be able to set breakpoints in the (unmodified!) MFC header, requires us to enable the Require source files to exactly match .. option.
If the option is disabled, which would imply a more lenient behavior by the debugger, it no longer works.
And, yes, we double checked it's always the same source file at C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.28.29910\atlmfc\include\cstringt.h
The mystery with step-into/F11 persists, but I guess this would better be taken to a separate question.
Uncheck the Enable Just My Code option in Tools->Options->Debugging
I know that works for c++ std:: library code debugging. The other technique I do, when I forget to uncheck this option, is similar to what you describe above.
Set a breakpoint on the line of code I want to step into.
When the breakpoint is reached, right click in the editor window and select "Go To Disassemly".
In disassembly mode, step over until you get to a call statement. That's typically the std library. Eventually, you'll navigate into a mix of assembly and system code sources. You can flip out of disassembly mode by right-clicking again and selecting "go to source code".

Section not created in program-release version C++

I am storing some variables inside custom section in my program. During debugging session I can check it is created and that it contains the necessary data. But in release mode, it disappears!
Note: I am also creating an executable section which strangely is created in both version. The CPU platform seems to make no difference.
Why doesn't the "data" segment appear in the release version?
This is a short snapshot:
// Defnitions used for better code segmentation
#define store_variable(x) __declspec(allocate(x)) //for data segment
#define store_code(seg) __declspec(code_seg(seg)) //for execution segment
#pragma section(".eqwrt", read) //weird name because I thought there would be collision
store_variable(".eqwrt") UCHAR USER_DATA[SIZE];
store_variable(".eqwrt") USHORT Version = 1;
store_code(".wsect") bool sendError();
The program (it's a dll) is compiled with a fixed base address and with /MT flag.
Release version x64. Only one segment appears-the executable one:
Debug version x64. Both segments show up:
Try to disable Link-time optimizatizon scheme from the project's settings.
To do that go to: Configuration Properties 🠂 General 🠂 Whole Program Optimisation and set to No Whole Program Optimisation.
Most likely it has something to do with the optimisations performed during linking.
More details you can get from here : What's C++ optimization & Whole program optimization in visual studio

XCode 4.2 static libraries linking issue

I have Core static library, a few Component static libraries that relays on the Core one, and then there is an App that links against both Core and Component libraries. My App can link both against Core and Component as long as Component don't uses classes from Core (App uses classes from Core).
I got the following error in both armv6 and armv7 versions. So my problem is not the very popular linking issue that everyone has.
ld: symbol(s) not found for architecture armv6
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I added reference to Core in Component and even added it in "Link Binary With Libraries" which shouldn't be necessary for static lib.
Since I start having this issue I start doubting my design... It probably makes more sense in dynamically linking environment but still it should be doable in static one, especially since this already works under Windows with MSVC compilers.
Edit:
I made some progress! Although I still don't know where to go with it.
Here is my setup:
Core has a class cResourceManager that has a templated method GetResource<T>(int id)
Core also has class cResource
Component has class cMesh that inherits cResource
Here are some tests:
If I try from App to call rm->GetResource<cMesh>(...) I get the linking error
If I try from App to construct cMesh I get linking the linking error
If I try from App to call static method that will return new instance of cMesh I get the linking error
If I comment out the construction of cMesh but leave other member cMesh function calls the App links fine. I can even call delete mesh.
I have never seen anything like it!
If you remove the cMesh constructor, then you are then using the default (no argument, no body) cMesh constructor that is given to you. It almost sounds like there's a build error or missing code as a result of some code in your cMesh constructor and so the library isn't actually getting generated, and perhaps Xcode isn't reporting the error. Xcode is no good at reporting linker errors.
I would suggest looking at what symbols the linker says are missing and double-check that they are actually defined in your code. My guess is that you're using one of those symbols in your cMesh constructor. A lot of times with virtual base classes, you may forget to define and implement a method or two in a child class. Could be a result of missing a method based on your template, or your template isn't #included correctly. This could compile fine but result in linker errors like you're seeing.
If Xcode isn't showing you the full linker error, show the Log Navigator (Command ⌘+7), double-click the last "Build " entry, select the error, and then press the button on the far-right of the row that appears when selected. The symbols should be listed there. If not, it's time for xcodebuild in the Terminal.
If it's not that case, I'd be interested in seeing the results of whether or not the library is being built for the appropriate architecture, or maybe this can spur some progress:
In the Xcode Organizer Shift ⇧+Command ⌘+2, click Projects and find the path to the DerivedData for your project.
In the Terminal, navigate to that directory (cd ~/Library/Developer/Xcode/DerivedData/proj-<random value>/)
Remove (or move aside) the Build directory (rm -r Build)
In Xcode, try to build with the cMesh constructor present.
Find the Library product file (cd Build/Products/<scheme>-iphoneos)
Your compiled static libraries (<libname>.a) should be in this directory. If they're not there, they didn't build (unless you put your products elsewhere). If your libraries are there, let's confirm that they actually are getting built for the appropriate architecture. Run otool -vh <library>.a. You should see something like:
$ otool -vh libtesting.a
Archive : libtesting.a
libtesting.a(testing.o):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 OBJECT 3 1928 SUBSECTIONS_VIA_SYMBOLS
As you can see, my test library was built for ARMv7.
Make sure you are linking them in the correct order.
If Component depends on symbols in Core, then Component needs to be first in the link order, so the linker knows which symbols to look for in Core.
In MSVC the order doesn't matter, but in most other compiler suites it does.
I don't think Clang generates code for armv6, if you're targeting devices that old you still need to use GCC.

Access violation on static library call

As an extension of question MSVC unresolved external symbol linking executables. A contains and a class P with two member functions F and G, and also contains a global P MyP. I'm attempting to call functions MyP.F, from Executable T. I finally got past the linking part, but now it fails at runtime with the exception.
A.cpp
struct P {
void F();
void G();
} MyP;
P::F() {
}
P::G() {
}
int main() {
MyP.F();
MyP.G();
}
T.cpp
struct P {
void F();
void G();
} MyP;
int main() {
MyP.F();
MyP.G();
}
I can put a breakpoint in T at the line where it calls F in Visual Studio 2008, but when I press the button to step in, or to step over, I get an exception First-chance exception at 0xfe5ca589 in A.exe: 0xC0000005: Access reading location 0xfe5ca589. When I look at the call stack, it shows
fe5ca589()
A.exe!G() + 0x60a6 bytes
[Frames below may be incorrect and/or missing, no symbols loaded for A.exe]
Both projects are part of the same Visual Studio solution, and A is properly set as a dependancy for T, and seems to be linking correctly, but I can't step into it. Does anyone have insights how to make Visual Studio load the symbols for A so I can step into it and find the error? (Or if something is linked funny causing the error?)
Executables don't have the metadata allowing them to be loaded at an alternate address, and A.EXE can't load into T.EXE at its desired address, because T.EXE's code is already there.
You might be able to work around this by changing the default load address of A.EXE (when building it, it's a linker option), but the correct solution is to use a DLL. (Confirmed, no you can't)
Exports from .EXE files are provided to allow plugin DLLs to call functions in the main application. They aren't meant to allow loading the .EXE like it was a DLL.