0

I am trying to build a static library as a release others can use (and they should be able to use it whether they debug their own code or not). My library on the other hand should not contain any debug symbols or so. I only want to release the headers and the .lib file (no .dll or so).

The User of the lib should be able to use his runtime-environment and build flavor (debug or release) without any hassle.

Is this even possible with Visual Studio ?
[==> I already have read, that some users switch over to build this kind of lib with gcc]

I have tried several cases and I always get something like "_ITERATOR_DEBUG_LEVEL" conflicts or so. Static linking of the runtime libraries seems not the solution too, but what else ? Is it possible to switch off all references and let the project incorporating the library decide what runtime to use ?

Even if this question is similar to the follwing I haven't found the correct answer there: Pure static C++ Library (no dependency of MSVC C++ runtime) or here Microsoft Visual Studio ~ C/C++ Runtime Library ~ Static/dynamic linking

Jesko
  • 85
  • 11
  • 3
    If you want the users to link against either Release or Debug then you wouldn't ship one lib, you'd have multiple for example `foo.lib` and `foo_d.lib` respectively. `_ITERATOR_DEBUG_LEVEL` is one such reason, but also optimizations, inlining, etc. Also consider which platform and architecture you will support (x64, Win32). This is typically why (in open source case) people instead provide CMake files so the users can build and link to your code in a way that is compatible with their current build configuration. – Cory Kramer Nov 30 '21 at 14:14
  • 4
    Is your pure static C++ library using a pure C public ABI? If it is not using a C ABI as a public API firewall, then you should release your pure C++ library as source code. Because as Titus Winters has said, "Build everything from source, with the same flags, at the same time." A pure static C++ library will impose the project to use the same flags and same compiler as the library... that applies to debug-or-not flags too. – Eljay Nov 30 '21 at 14:16
  • Yes, visual studio provides some guarantees for mixing compiler versions with shared libraries, for static libraries everything has to match – Alan Birtles Nov 30 '21 at 14:19
  • ***I always get something like "_ITERATOR_DEBUG_LEVEL" conflicts or so.*** Means you are mixing debug and release. Remember that debug and release need separately compiled binaries for `c++` based code. It's undefined behavior to mix Debug and Release (because the API is implemented differently in debug) so thankfully now Visual Studio makes it more difficult. – drescherjm Nov 30 '21 at 14:29
  • @Cory: I only want to release the release-version of the lib (64-bit), but I don't want to prevent the users from debugging other parts of their code ... – Jesko Nov 30 '21 at 14:32
  • You must produce both debug and release binaries if you want them to be able to debug. Otherwise you would have to not use the standard library in the public interface. – drescherjm Nov 30 '21 at 14:33
  • @Eljay: Releasing the source is a no go here, but I find it interesting what the need for "with same flags, at the same time" is ... A library is a collection of compiled, but not linked objects, with several function and defined interfaces for parameters and return values, why do we have to provide more information than this ? – Jesko Nov 30 '21 at 14:38
  • @drescherjm: exactly that is my question: How to "not use the standard library in the public interface"? And what do you mean with "public interface" ? – Jesko Nov 30 '21 at 14:40
  • 1
    In msvc the standard library has a different implementation in debug mode than it does in release mode. Iterators are larger to have the ability to debug ... – drescherjm Nov 30 '21 at 14:40
  • 1
    If you don't have any use of the standard library in the headers that you give your users to use you can use the release compiled library in debug mode. That means no usage of std::string, no vectors no containers ... in any of the headers that your users see. – drescherjm Nov 30 '21 at 14:42
  • 2
    If your C++ library uses a public C ABI and hides away the private C++ implementation details, then you do not need to provide more information than the public functions and public return values. – Eljay Nov 30 '21 at 14:45
  • @drescherjm: I believe that your hint with std::string is the key. I will try that out. Thank you all so much !!! – Jesko Nov 30 '21 at 14:50
  • 3
    You also shouldn't `delete` (or `free`) what your users `new` (or `malloc`), and vice versa, *unless* you are sure they have the exact same version of the C++ runtime as you do. If you allocate something and return the user a pointer to it, you should also provide a deallocation function for this object. Almost none of the above is a concern if both you and your users use `g++` or `clang++`. You then can mix and match compiler versions and debug modes, and expose as much C++ in your public API as you want, – n. m. could be an AI Nov 30 '21 at 15:55

1 Answers1

2

The solution is as follows (as stated by @drescherjm and @Eljay):

You can build static libraries (.lib files) with VisualStudio (currently VS2019) that are usable within debug and release environments if only "C ABI" is used and exposed to the "outside" (the header file(s)).

"C ABI" does NOT mean, that no C++ functionality may be used, it means that no "std::*" functions/containers/etc. may be used.
Neither as function parameters nor as class members.

#ifndef LIB_STATIC_H__
#define LIB_STATIC_H__

#include <stdint.h>

class MyLib
{
public:
    MyLib();
    ~MyLib();
    uint64_t TestFunc(char* param, uint32_t x);
};

#endif

This will work, but this NOT:

#ifndef LIB_STATIC_H__
#define LIB_STATIC_H__

#include <stdint.h>
#include <string>

class MyLib
{
public:
    MyLib();
    ~MyLib();
    uint64_t TestFunc(char* param, uint32_t x);
private:
    std::string m_MyString;
};

#endif

The above example works, because there was no use of std::* functionality in the program incorporating the LIB (not shown here).

But if you need to use std::* functions/templates outside the static-lib, there is still the _ITERATOR_DEBUG_LEVEL conflict existing ...

Jesko
  • 85
  • 11
  • 1
    PIMPL can also help with moving the implementation details and usage of the standard library out of the public interface. – drescherjm Nov 30 '21 at 16:46
  • 1
    Exposing in the headers doesn't matter, you can't use the standard library full stop in the static library – Alan Birtles Nov 30 '21 at 19:04
  • @AlanBirtles: According to my own tests this is NOT true. I simply used a std::string to generate and output a string in the CTOR of the example class without exposing something to the outside and this worked. The static library was usable without errors in debug and release of a different project. – Jesko Dec 01 '21 at 11:18
  • 1
    well I did a similar experiment and it didn't work, failing with the same `_ITERATOR_DEBUG_LEVEL` error as the OP – Alan Birtles Dec 01 '21 at 12:26
  • Just check it out by yoursef: https://gofile.me/5bS9t/PGlMzShY3 – Jesko Dec 01 '21 at 12:31
  • There are two solutions. The first (libstatic) generates a .lib as release-version and copies in the After-Build-Step the library and header to the second project (libstatic-test). This can be build with debug- or release mode and works. – Jesko Dec 01 '21 at 12:33
  • @AlanBirtles Looks that you were finally right. Further experiments reveal that adding some std::* functions to the main project lead to conflicts then. My example uses only std::* functions within LIB, but not in the project incorporating the lib ... too bad. – Jesko Dec 05 '21 at 16:16
  • 1
    ah, yep, didn't spot that was the difference between your experiment and mine – Alan Birtles Dec 05 '21 at 16:29