There is considerable cost (and pain) for developers to debug external libraries due to the fact that many libraries are distributed in two editions: one with debug information, other without. The developer has to search and download debug files, and point the debugging environment to their location. This is often a painful and error-prone task. There is also a lot of work related to build and distribute those libraries.

At same time, the world changed in ways that make the "release" version (ie the version without debugging information) obsolete. For instance:

  • A modern runtime can efficiently strip debugging information, optimize on-the-fly and run the program at full speed. Examples are the JVM and JavaScript interpreters.
  • Open-source projects, or binaries that are not published outside the company, have no reason to be obfuscated. Also, given that many modern languages now support reflection, obfuscation by stripping debug information is very limited, if effective at all.
  • Disk space is high, disk performance (SDDs) is getting better and better, and network bandwidth is improving as well.

Please note that this question is limited to libraries. I'm 100% OK about distributing applications without debugging information, which is actually extremely important in the mobile world.

After a lot of trouble with .NET PDBs, and .class files without debugging information, I think we should evolve processes and tools into a world where the default is to compile and distribute libraries with full debug information, embedded in the binary (like .class files) if that's possible. After all, the only remote reason for not doing that is protecting copyrights (which doesn't apply to many scenarios).

Of course, the tools that pack applications should be smart enough to search and destroy every piece of embedded debugging information before publishing for download. This is based on the fact that end-users seldom debug applications.

  • At everywhere I've ever worked as a developer, it's been the policy to never use any third-party library if there is no source available. Everything is either open-source or a commercial library with full source code included as part of the license. This way, you don't have that problem. – Mason Wheeler Feb 10 '17 at 22:13
  • 1
    If you develop libraries that are sold, obviously you should provide at least Release version. If user bought source code, then you should provide projects or makefiles for both so that user can rebuild them. If your library is quite small and does not have a too much configuration (static/dynamic, debug/release, Ansi/Unicode and which run-time is used), then you might provide precompiled version of all or common cases. When you ship an application to an end-user, you should always ship the Release version. Debug version can do a lot of extra validation that could easily kill performance. – Phil1970 Feb 11 '17 at 19:53

It might also be a question for your lawyers.

A library (or an executable) compiled with debug info (e.g. in C++, on Linux, compiled with g++ -g2 -O2 into ELF format with DWARF debug info) contains a lot of [meta-]data which facilitates the reverse engineering of your code.

If you release that thing to outside clients, you expose some of your industrial/intellectual property to them (in particular all your data structures, the class hierarchy, the name of your files, classes, functions, variables, etc...). Decompilation of your code becomes much less difficult (even if it stays quite hard).

Also, the debug information takes a lot of space. That might have some cost (bandwidth, data volume) when deploying your software.

BTW, producing open source software facilitates even more your work, with the potential benefit that some outside contributor might slightly improve it.

If you can (i.e. you want and you are allowed to) release debug information, indeed it is simpler to release some binary (of your library or of your program) with debug information included in it (and not in a separate file). Notice that many compilers are able to optimize and still emit debug information (e.g. with GCC you can compile with both -g -O2 flags; the debug information is there, but is "approximate" because of optimizations).

| improve this answer | |
  • 1
    This answer misses the fact the OP is talking about a situation where he already willing and allowed to distribute debug information - just separated, by providing two different packages. The question is not if one should distribute libs with debug information - it is if this needs to be done in two packages. – Doc Brown Feb 10 '17 at 8:29
  • I'm understanding the the OP is keeping that debug information, not releasing it, in the alternative scenario – Basile Starynkevitch Feb 10 '17 at 8:31

The idea proposed here is that shipping debug information with a software library makes developing applications easier for that library. If this is true, it implies that programmers need inside knowledge of how the library code works in order to get their own code to work. This is what is known as a bad smell. If it is true inside knowledge helps programmers then the library and specifically the boundary functions are not well thought out or clean. Supplying debug information in this case is a hedge against poor engineering and poor documentation.

You know you are in trouble when all the code the engineering team releases had to be compiled for "Debug". I've seen my share of released production level code that is compiled for debugging because the programmers can't solve problems in the released version of the code without it. They can't debug without a debugger and the code has not been made to be debugged any other way. So the released code becomes always debug code. I've been caught many times in this cycle as an engineering manager.

I've run into libraries that have internal uncaught exceptions; another bad smell. This is caused by lack of checking parameters and data integrity at the boundary of the API. You know when there is one exception used for many different error situations saying something unhelpful like "bad things happened" then you are dealing with unclean code. Hold your code to a higher standard so that boundaries take care of internal errors and shield the library from poor calling code. Perhaps there is some kind of logging that can be used to aid in diagnosing runtime errors even in production.

Another reason not to supply debug information is the code that calls the library could make assumptions about the internal workings of the library itself violating information hiding. This is a business problem because it becomes hard to make changes to the library in future releases without breaking other people's code. The more assumptions made by calling code there are, the harder and more expensive it is to supply new versions of the library.

The art of programming has come a long way and programmers are orders of magnitude more efficient these days at producing quality code. In particular, the powerful debugging capabilities of IDE's like Visual Studio and Eclipse make it much easier to pump out large volumes of high quality code. However, there is a price to be paid. Because of these tools, programmers have built in very little in the way of runtime diagnostics that can be used to find a problem in production code. Many programmers never learn the skills to fix bugs unless they can reproduce them in a debugger. This makes for big trouble when a bug emerges in production code and all the customers are screaming but, the programming staff can't reproduce it.

Nothing replaces clean code and a great self documenting API. Letting programmers supply debug code instead is a cop-out.

| improve this answer | |
  • 4
    There is some truth in what you wrote, but IMHO also some over-idealism. Even if a lib is intended to be clean, well-documented with clear boundaries and should in theory need no debug information when used by someone else, no real world lib is free of bugs and design errors, and providing the debug information as an additional tool is far from beeing so bad as your answer pretend. – Doc Brown Feb 10 '17 at 13:11
  • Doc Brown, I am going to add a little based on your comment. – Jack D Menendez Feb 10 '17 at 17:23
  • You are talking about prevention, I'm talking about remediation. It's naive to believe everything can be prevented. By this rationale, we should avoid having firefighters and ambulances. There are countless teams making all kinds of libraries, and they suffer pressure in different levels and ways. We cannot assume they will always be able to produce detailed documentation and full diagnostics capabilities. On the other hand, using a flag that embeds debugging information would be very low-cost. – fernacolo Feb 10 '17 at 20:31
  • Remediation, I understand; believe me I've been there. I totally understand the problem. It's kind of like building a city with no building codes. At some point bad things will happen. I don't have a good answer to the business that producing crappy code is a business case because it decreases time to market. Personally, I don't think business people understand the problem and in the various ways their business is affected by poor quality. Does it really take that much longer to produce better quality? I don't think it has to. – Jack D Menendez Feb 11 '17 at 0:50

No, we should not. People who conditionally include code executed in debug builds expect that code to be executed only in debug builds, and never in release builds. This code may only be invariant checking that is very slow. Or it may be code that could expose security vulnerabilities. Regardless, you have to assume there is a reason that code was only intended for debug builds.

The real solution is to create libraries robust enough that no one needs the debug information. This means better library design, better error handling, more inclusive automated testing, etc.

If the user of a library also has to debug that library, they are wasting their time. The library may be incredibly complex internally. It may take a long time to debug the problem. And the "solution" determined may be completely incorrect, due to a lack of complete understanding.

| improve this answer | |
  • 1
    You ignored my citation on how modern runtimes work. They strip debugging code on-the-fly. You also ignored that in open-source world, binaries are useless to prevent code from being analyzed. You assume that every team have resources to create the "state-of-the-art" release, and that there are never beta or preview releases. And you assume that debugging is used only to fix problems, when actually it's also useful as a learning tool. – fernacolo Feb 11 '17 at 0:40
  • @fernacolo With open source libraries, you can build it however you wish (debug or release). My point is that debug builds don't just contain symbols. The code is different. And we should encourage the development of higher quality libraries. Bugs can not only cost money. They can cause physical harm. – Frank Hileman Feb 13 '17 at 8:04
  • @Frank_Hileman Now you are assuming that building an open source library is as easy as simply using the distributed binary with debugging information already embedded. Also, for any modern language, debugging code should not be different from production code. As explained, it's trivial for a runtime to strip debugging code on the fly. I know that bugs can cause physical harm, but that doesn't prevent people from releasing poorly documented code. – fernacolo Feb 14 '17 at 21:02
  • @fernacolo release builds strip out more than symbols (in fact symbol stripping is independent of release vs debug); typically developers include code in debug builds that is conditionally compiled. This code is not present in release builds. It cannot be automated. – Frank Hileman Feb 14 '17 at 22:38
  • @Frank_Hileman. I know how release builds work. The point is that debug mode can be defined at runtime (for instance, see -xdebug option in docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/…). Plus, you can have a runtime flag to tell if debug is enabled or not - see here: stackoverflow.com/questions/1109019/…. With that flag in place, a code full of debugging symbols will run as fast as if it weren't. See oracle.com/technetwork/java/tuning-139912.html#section3.1. – fernacolo Feb 15 '17 at 0:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.