Another cpp nightmare.
Debugging managed libraries remotely was rather easy. Have the remote debugging tools installed, run the code on the remote machine, attach to it via your local VS, have the right pdbs ready, done. You're debugging.
Of course, you should be sure that the pdbs actually match the dlls. That can be checked with an appropriate tool.
For native code, apparently, the debug symbols need to be placed into the same directory as on the remote machine. Like, if it's remotely in "C:\some\where\strange\myProg.exe", then you need to create this strange directory on your local machine as well.
I didn't find anything on the web which explicitly stated that.
Here are some other links, which might be of help:
http://www.codeproject.com/Articles/146838/Remote-debugging-with-Visual-Studio
Remote Debugging and Diagnostics (vs 2013)
and, of course, a most cited resource about pdb files in general (native and managed):
http://www.wintellect.com/blogs/jrobbins/pdb-files-what-every-developer-must-know
But they seem to deploy directly what you build to a remote machine, instead of having corporate release builds installed on them and then debugging them with the pdb files which the build machine thankfully published as well.
Freitag, 5. Dezember 2014
cpp c++ linker warnings which look like name mangling problems but are cause by classes not being exposed in the dll
Today, I wanted to write some tests for a cpp dynamic library under windows.
Such a build still generates the .lib file, like for static libs, but this .lib file only contains some header information or somesuch.
In the end, the .dll will be used.
Then, when I tried to compile the tests, I got this:
After several hours of despair, I found out that the class:
Swarm::SpecificChainer
was declared like this:
But should have been declared like this:
The keyword is DLL_PUBLIC which will expose this class to the users of the dynamic library. See here on gnu.gcc.org for further information. All non-exposed classes are only visible internally.
I still don't know, why it's done like this, whether this is only on windows (can't remember that on linux) and if it's common for all dynamic cpp libs, why they didn't invent some smart keyword for that, like in c#: internal.
Such a build still generates the .lib file, like for static libs, but this .lib file only contains some header information or somesuch.
In the end, the .dll will be used.
Then, when I tried to compile the tests, I got this:
1>SwarmTests.obj : error LNK2001: unresolved external symbol "public: __thiscall Swarm::SpecificChainer::SpecificChainer(long,class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > const &,class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> > const &,class Swarm::ZergLink *)" (??0SpecificChainer@Swarm@@QAE@JABV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@0PAVZergLink@1@@Z)
1>C:\dev\mycode\SwarmTests\Debug\SwarmTests.exe : fatal error LNK1120: 1 unresolved externals
After several hours of despair, I found out that the class:
Swarm::SpecificChainer
was declared like this:
class SpecificChainer {
ctor...
...
}
But should have been declared like this:
class DLL_PUBLIC SpecificChainer {
ctor...
...
}
The keyword is DLL_PUBLIC which will expose this class to the users of the dynamic library. See here on gnu.gcc.org for further information. All non-exposed classes are only visible internally.
I still don't know, why it's done like this, whether this is only on windows (can't remember that on linux) and if it's common for all dynamic cpp libs, why they didn't invent some smart keyword for that, like in c#: internal.
Dienstag, 14. Oktober 2014
Modular build scripts with NAnt
We are using NAnt for our build process. Since the product is large, this amounts to things like this:
- clean up the source tree => clean slate
- build all projects (~50 mins) => compiled libraries and executables
- run all tests (~2 hours)
- run benchmarks
- create installer (msi/bootstrapper)
- publish to a file share
This all amounts to several thousand lines of nant code. And because we know naught about modularizing things and decoupling things, this all becomes basically one big nant file. That is not maintainable.
We tried to modularize things a bit by putting common code into nant files, like this:
<include buildfile=".\installer.prop" />
which are just included by other nant files. So, we kind of reduced code duplication a bit.
Problems remain:
- you don't know where your property has been set for the first time
- if it has been reset to something else
Additionally, we have to deal with the problem that by using nant we have to use a declarative language to do loops, maintain file lists, have few insight in how properties are kept in memory.
It's even difficult to see the workflow of this whole monster.
I currently think, that for such large projects nant is the wrong tool. I'd like to try rake.
However, maybe we're just using nant the wrong way.
There is a way we should use more to modularize all those build scripts and make them independent:
- separate nant files, each of which does one thing, and one thing well. Kinda like the Single Responsibility Principle. It's code, after all.
- have integrating nant files which call other nant files. Those integrating nant files should not have logic.
- when calling other nant files, do not inherit the properties of your current state (to inherit is actually the default).
In practice, this would look like this:
<project name="integrator" basedir="."> <property name="baseDir" value="${project::get-base-directory()}" /> <target name="build"> <!-- we integrate stupid targets here. they do not contain logic, they just call someone else --> <call target="cleanBuildfiles" /> <call target="buildSoftware" /> <call target="buildInstaller" /> <call target="publishSoftware" /> </target> <target name="buildSoftware"> <!-- inheritall="false" prevents the called nant scripts from inheriting all what we already might have screwed up. It's a fresh start. An error in this script doesn't affect those other scripts. Modular :) --> <nant buildfile="${baseDir}\myFramework\default.build" target="buildAll" inheritall="false"> <properties> <!-- if that nant script depends on a certain global variable, inject it --> <property name="CCNetLabel" value="${CCNetLabel}" /> </properties> </nant> </target> <target name="buildInstaller"> <nant buildfile="${baseDir}\installer\default.build" target="buildInstaller" inheritall="false" > <properties> <!-- or directly give an apt name to such input variables --> <property name="BuildNumber" value="${CCNetLabel}" /> </properties> </nant> </target> </project>
I can't yet say that this will make nant easier to use, but I already feel that I have a better overview of what is done where. Maybe it will help me keep order and find errors in the future.
Abonnieren
Posts (Atom)