14

I'm relatively new to C++, so I'm not sure how I should best handle small dependencies (e.g., a scripting language, or a JSON/YAML/XML Parser).

Should I create separate projects and link them as static library, or are there downsides of just putting the .h/.cpp files into my main project?

The latter seems a lot easier because I've spent several hours dealing with incompatible libraries (different compiler setting when building the library), but I don't want to start off learning C++ the wrong way.

If it's preferable to keep them as separate libraries, how would I best keep compilation flags in sync so that the .lib/.a files successfully link to my application?

(I'm currently working with MSVC 2015, but the goal is to compile on Mac OS X and iOS using XCode/clang, so that I have to deal with at least 3 different types of libraries (Win x86, Mac x64, ARM))

  • 5
    Gaze into ABIss and they will look into you – Basilevs Mar 26 '16 at 20:26
  • 1
    Bear in mind that some libraries are intended to be used this way. The SQLite library's preferred usage pattern is to drop the amalgamated source and header file into the source tree of a C or C++ application to compiled into the executable. – Mark Benningfield Apr 1 at 22:21
6

TLDR;

Should you add the source? YES
Should X add the source? DEPENDS

Here comes the why...

Back in the day, compilation time was an issue even smaller projects had. Compiling your sources and never worrying about caching compiler results was definitely appealing to some. That's one point for libraries irrelevant to you.

Another important one is versioning. Do you really need to version each library separately? Run tests against each one? Distribute it amongst many team members? Libraries are great if you do, and convenient to move around, but again, seems you don't care about this either.

Final point here is, it's an added overhead, and dropping the source files is easier in your case, which gives a very strong point to dropping in the sources rather than using libraries. As you have noticed, once you make a single compiler setting change, you have to chase all the dependencies otherwise.

I know all this from experience:

For Swift projects, I definitely use frameworks (libraries) and link against them, since it's easy to configure using Xcode. I also really need the versioning, tests, and decoupling there, so that's why.

For Mono (C#) projects, for Unity, I started with the hip approach of breaking down the project into libraries, compiled and tested each one, which was great... but once I dropped the libraries into Unity, all sorts of issues happened, from the hacked version of Mono Unity uses, to simply the sometimes different behavior the code exhibits when changing platforms. Not having a single IDE here to manage all the libraries was a true pain, so putting all source within Unity was a huge win for productivity.

Finally, most relevant to you, a C++ game project I worked on. A game engine, network realtime client, network HTTP client, AI, and a persistence store were written for this game, just on the client side. What did I opt for? CLion + Libraries. Even though I was using libraries, it didn't feel like I was. All the sources were in the CLion IDE project, and by composing CMakeLists, I was able to trigger all builds and link them in a single stroke.

As a conclusion, I would say using libraries is a future-proof solution, but also a premature optimization if not needed. As far as I could ascertain from your situation, switching from MSVC to Xcode will be a pain if you are gonna have multiple build target. So, just drop it in and maintain as much isolation as possible for when the time when you might need to use libraries.

P.S: I am having a similar dilemma these days with docker. Should I compose? Should I just run locally? .. etc. Also Elixir, as it allows you to build Applications within the same application.. Should I do that? Or separate the app into the so-called micro-services? ... etc. There is no silver bullet, always measure yourself, as YMMV.

2

Linking with C++ libraries require a lot of hassle, and it requires lots of knowledge and effort to do it correctly. It can be intimidating to C++ learners.


Often times, the authors/maintainers of a specific C++ library will have this in mind, and will recommend one way or the other.

In other words, if the authors/maintainers intend the library to be included by headers (*.h and .hpp only), or include by source (.h*, or .c), it would have said so clearly in the readme or documentation.


Libraries that are designed and maintained to be cross-platform (and compatible with multiple C++ compiler vendors and environments) will often have a makefile system or a build configuration system (such as CMake). These systems are used to generate header shims that smooth out platform differences, and to generate scripts that will invoke the compiler and linker on source files using the proper command-line options and in the correct sequence. Depending on the platform and configuration, these build systems may include or exclude certain headers or source files, or they may define or undefine certain preprocessor symbols.


Going against the authors/maintainers recommendation is possible, but that always require an extensive porting effort. The amount of work required for that porting effort can be comparable to porting to a different C++ environment.


Because Visual C++ uses its own build system based on a project description file (partly XML-based), it is quite unlike the scripting-based build system used under Linux. The approach used by CMake is for CMake to take the configuration settings, and then emit the entire Visual C++ project structure, with the configuration options baked into the *.vcxproj files.

If issues arise during C++ linking with Visual C++, the build settings in *.vcxproj files can be modified using the Visual Studio GUI (using its project property pages dialog). This assumes you understand thoroughly the meanings and the consequences of a dozen of important C++ compiling and linking settings.

Now comes the stupidest part of using Visual C++: if you are using a dozen different third-party libraries, changing the build settings for all of them means going into each *.vcxproj file, and repeating the same change on the GUI for a dozen times. A hassle, but it can be done, if you know how to do it correctly.

Most Visual C++ learners learn these settings the hard way, by observing Visual C++ compiler and linker errors, identified by their error code. For example, one may look up LNK2005, with the superficial meaning of "The symbol symbol was defined more than once," but with the understanding that the duplicate definition does not arise from a careless programming mistake, instead it could have happened because of some conflicts or misapplications of compile and linking options.


To provide a more specific and useful answer to your situation, one will need to know the names of the libraries you intend to use, as well as the linking errors or other difficulties you encounter. You may find existing answers to those questions in the respective library's discussion boards. These questions tend to be tagged with "linking issues", "windows", and "visual C++".

A beginner-to-expert guide on this issue is possible, but it is going to be project-specific. Different preferences chosen by different projects will require a complete rewrite of the guide.

  • If you use CMake to emit .vcxproj, rather than modifying the .vcxproj you can modify the CMake config – Caleth Apr 2 at 9:08
1

I would say yes, as long as it is easier. There are quite a lot of benefits:

  1. It will result in faster and better code, especially if you turn on Link Time Optimisation.

  2. Your IDE will like it more, e.g. it will (hopefully) allow you to jump to the implementation (.cpp) of library code, rather than just the interface (.h), which is extremely useful when working with badly documented code (i.e. most code).

  3. It often allows you to add the dependency as a git submodule, which is a slightly hacky but actually pretty good way to have dependencies (for C++ anyway, which has pretty much no sane build systems). It makes it really easy to update the library and test different versions.

  4. You don't have to worry about a dependency being compiled with MSVC++ 2013, while you're using 2017 for example. Or shared vs static MSVCRT.

  5. You can easily build in debug mode and step into the library.

The only reason I think you would not want to do this, is if the library is large and has a complex build system that you do not want to replicate in yours, e.g. Boost or LLVM. But for simple libraries there is no downside really.

As an example, I use libusb in a few projects, and I need to support Windows. libusb uses autotools which is a joke of a build system and doesn't really work on Windows anyway. They do provide precompiled binaries but they are built with MSVC++ 2013 and won't work with 2017. The easiest solution by far was just to add all the relevant .c and .h files to my project.

  • 2
    1) really? A static library is just a collection of object files, just like if you had just compiled them. – Baldrickk Mar 27 at 17:14
  • You can make an archive of .o files that have been compiled with -flto but those aren't really a static library - for Clang they are LLVM bitcode files. And it obviously won't work if you use static libraries that somebody else provides. – Timmmm Mar 28 at 16:32
  • ok, lets upgrade this discussion - I'm looking forward to learning some more things :) – Baldrickk Mar 28 at 16:40

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.