How to write truly cross-platform C++ libraries for distribution - c++

The problem:
I'm writing an SDK that is primarily C++. The source code will be licensed to developers who pay for it, and the output libraries and include headers will be free for public usage. The SDK will target a plethora of platforms including Windows, Xbox, Playstation, Android, iOS, Mac OS X, and Linux. I'm a kind of guy who mostly likes Visual Studio and usually develops software using Windows machines. In the last few years, Visual Studio has made this quite a lot easier than it used to, where I have a mostly clear path to target all the previously mentioned platforms using a Visual Studio set of project files as the source of truth that brings all my source code files together... except for Mac OS X, unfortunately. Visual Studio is able to build executable code for iOS and Linux by remotely interfacing with a Mac or Linux box respectively for compilation and debugging, which is really quite cool, but for some reason Mac OS X as a target is left out here. Additionally I'm well aware that there are plenty of other professional developers out there that don't write code on Windows machines, nor do they have any interest in buying a commercial license for Visual Studio.
The question:
Since C++ still does not yet have a build system standard, and may not ever, how do I maintain a single source of truth that maintains the build configurations for all my source files targeting so many different platforms while simultaneously minimizing the barrier to entry of supporting software developer clients who need to build, run, and debug my source code?
Possible answers I'm aware of:
A) Visual Studio projects remain the source of truth from which any other C++ project types (such as Android Studio, XCode, and .make files) are derived. I'm aware of tools that can convert VS to .make and the like, but haven't actually tried them yet (my source code base is starting to get somewhat large already). Or I could just bite the bullet and write them by hand and try to keep them all in sync.
B) CMake. Sigh. So frustrating that it's very popular, and seems to exactly solve my issues, but it has its own set of problems that seem to be deal-breakers. For starters, once you go in on CMake, you pretty much can't come back. Using Visual Studio and property sheets, I've been able to tweak my build configurations with properties that are mostly inherited and rarely duplicated across projects and configurations. As far as I can see, CMake doesn't care about respecting such things, and for common properties, it just duplicates them on all vcxproj files. To make matters worse, all file paths it generates in the output projects are absolute, not relative, and to top it all off, it forces anyone else who builds your code to use CMake, disallowing distribution of the project build files it creates without it. Also, does this even work for game consoles? Last I checked I couldn't find a reasonable way of supporting them without hacking the source code.
C) Roll my own script that's similar to CMake, but allows redistribution of its output projects, and supports all the platforms I need. It goes without saying that this would consume a lot of dev time.
Any other options I'm missing here? Your input is greatly appreciated.

I agree with the comments from #Scheff and #arrowd. Use CMake. I have built and deployed software to multiple platforms and CMake is the best, though not perfect, solution I have found for building C++ code.
I have not had to hack the cmake code to get it to work on various platforms.
Do not worry about properties being duplicated in vcxproj files. With CMake the build language is in the CMakeLists.txt file(s). The vcxproj files are generated code. As long as you are do not have redundant cmake logic, you should not care about replicated properties in the generated vcxproj files. Similarly, you should not care that the generated vcxproj files have absolute paths; you do not reuse the vcxproj files you reuse the CMakeLists.txt files and regenerate vcxproj files for each new platform or build.
Use the top-level CMakeLists.txt to define the properties that are common to all targets. Then in individual target(s) CMakeLists.txt files use target properties to tweak builds of specific targets. In my experience the replication of properties in the generated files helps because they make the builds more consistent; I am able to minimize replication in the source CMake logic.
Various IDEs (VS 2017, CLion, QtCreator) can use cmake based projects directly.
There is nothing cmake specific about the generated artifacts. The headers, libraries (and dlls), and executables of our SDK are standalone artifacts. Yes, cmake can make it easier for your SDK users but using CMake in your SDK will not force your customers to use CMake.
Have you tried CMake and not been able to use it? Or are you looking for something better? There are certainly multiple C++ build systems, but despite its shortcomings I believe CMake is the best one available right now.

Related

Use VS Code for Cross-Platform Scalable C++ Project

This tutorial provided by the VS Code team explains how to setup C++ in VS Code with MinGW (https://code.visualstudio.com/docs/cpp/config-mingw), however it seems to only target small-scale projects as it is configured to rebuilds all files each time, and isn't setup to allow for easy configuration of a project (global defines, adding link libraries etc.) (or am I missing something?).
I am looking into using CMake as my build tool inside VS Code, however am really turned off by the idea of having to update the CMakeLists.txt file to change my project's configurations, e.g. every time I add files to my project or link a new library, as I have grown up using IDEs who do this process for me, which I find magnitudes easier as it allows me to purely to focus on writing code.
My question is, is there a known method to setup VS Code that will allow me to use a tool such as CMake without having to tinker with it too often?
This tutorial seems like a good starting point to setup CMake, but its method requires CMake knowledge https://pspdfkit.com/blog/2019/visual-studio-code-for-cpp/
I ideally would like the setup to cater for both small-scale and large-scale projects, both of which should allow for cross-platform building.
Thanks
As Visual Studio Code is not a heavy weight IDE, you will need to put some effort to get it run the way you want it to have, either:
Write a CMake InputFile generator, e.g. :
list(APPEND EXECUTABLE_LIST executable_1 executable_2)
list(APPEND LIBRARY_LIST library_2 library_2 library_3)
foreach(lib IN LISTS LIBRARY_LIST)
add_library(${lib} STATIC ${lib}.cpp)
endforeach()
foreach(exe IN LISTS EXECUTABLE_LIST)
add_executable(${exe} ${exe}.cpp)
target_include_directories(${exe} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(${exe} ${LIBRARY_LIST})
endforeach()
or you could also use Visual Studio Code CMake Tool extention
For sure, you couldn't expect the highly functionality like Visual Studio in VS Code as they serve different purpose (highly specialised, deep system couple but slow and big vs small, fast, highly configurable).

How to generate vcproj files?

Suppose I've got a cross-platform C++ library, let's call it ylib. My primary development platform is Linux. I'd like ylib to be buildable by MSVC (2008, 2010, 11, etc).
What's the best way to do this? Do I generate .vcproj files? If so, how? Ideally I'd be able to generate them without using Windows myself. No extra dependencies should be required for Windows.
Multiple variants should be build: debug dll, debug lib, release dll, release lib with dynamic runtime and release lib with static runtime.
You could use cmake for your build scripts. Cmake has the ability to generate visual studio project files from the cmake build scripts. So you'd just need to distribute your cmake files, then individual people using windows could generate MSVC project files from that.
Though as pointed out in the comments, it'd be difficult to guarantee that you could actually build your project under visual studio without trying it out yourself.
EDIT: Though I've just realized that you requested no extra dependencies on linux, which this would not solve. Unless you generated the vcproj files yourself using cmake, and distributed them. But personally I think it'd be better to just have the cmake dependency. It's freely available, and easy to install.
This also has the advantage of supporting whatever version of visual studio your end user happens to have, without the need for distributing several different formats.
You just need to understand the format of vcproj files and then write them - they are simply XML.
I don't know how well MSFT document the settings (not very if history is a guide) - so for simple projects I would just create a project in MSVC and look at what it writes.
Alternatively you could just use cmake which already does this.

Does Visual Studio 2008 use make utility?

I have checked in buid directory and have not found makefile there. How does Visual Studio 2008 buid the project? Does it use makefile?
The NMAKE utility has been distributed with Visual C++ since back when it was called Microsoft C/C++ Optimizing Compiler, and is very similar to Unix make. Previous versions of the IDE actually used NMAKE makefiles, but this isn't true anymore. You can write NMAKE makefiles yourself if you want, but it sounds like you want to know what the IDE does.
Starting with VS2010, the build system changes to MSBUILD, which bertelmonster mentioned. But not in VS2008.
In VC++ 6.0, C++ projects have their own build engine integrated into msdev.exe.
In VS2002 - VS2008, it's a separate tool, VCBUILD. But you can still invoke it via the main IDE, devenv.exe, see the /BUILD option, and devenv is the best way if you have inter-project dependencies in your solution.
VS9 doesn't use makefiles by default the way Linux-flavored IDEs might. Instead, VisualStudio uses 'solution' and 'project' files. A Project file (*.vcproj for C/C++ projects) is basically a replacement for makefiles, and contains instructions, compiler directives, flags and everything else needed to compile a single 'project'. In this parlance, a project is a single output file, such as an EXE or DLL. But this same mechanism can be used to produce any kind of output, including TLBs, text files, widgets and ice cream cones (if your machine has the capable hardware :) )
A 'solution' is a collection of projects, and the solution file (*.sln) contains lists of projects needed to build an entire application suite, typically. It also contains dependancy information, so that the projects are built in the correct orders.
Solution and project files are human-readable text, but in the VS world you would virtually never want to edit these files yourself the way you would tweak a makefile by hand. Instead, you would use the IDE to change compiler flags, preprocessor directives, output directories, and all the rest.
That is how VS works by default, but VS is also capable of using makefiles in much the same way as Linux-flavored IDEs. It still uses solution files in this case, so you can mix projects that use makefiles with projects that use project files within the same solution. The VS IDE is actually quite powerful in this regard, and gives you the ability to do pretty much whatever you want. This power however comes with a price -- with so many features and capabilities available in the IDE, it can be rather complex and takes what you might think is an unwarranted ammount of user brainpower to fully understand.
If you want to create a makefile project, you can do so by doing File>New>Project... and then selecting Makefile Project from the main Visual C++ list of project templates.

How are open source projects in C/C++ carried out exactly without .sln/.project files?

Seems most open source projects in C/C++ only provide the source code,i.e. nginx
Is this a convention that anyone interested in joining the developing team should figure out the .sln/.project files himself to qualify??
most open source projects are coming from the linux side of computing. thus, they are mainly using unix style build tools, as well as open source compilers.
the main build tool is make, which uses a makefile to know how to build a project. on Windows, the main open source compiler is MinGW which is a win32 port of gcc. the use of those tools allows to keep a maximum of common things between unix and windows.
note that .sln files are specific to microsoft compilers which are not free to use (and are rather costly), they are not portable and so are not suitable for multi-platform programming.
Some projects use CMake, which can generate project files for Your Favourite Build System, but as mentioned above, you don't need to use .sln and pro files, even if a project is built with the MSVC compiler, MinGW + makefiles, or scons, or CMake, or any other number of scripty methods to invoke the right commands to compile the program will work just fine.
Don't confuse the IDE with the compiler!
No, most opensource project do not use MSVC solutions as they not portable and very weak in terms of features.
In most cases they use what is called "build-system" like autotools, CMake or SCons.
These build systems include information about:
source code and how to build it
various system checks that should be done (like find various 3rd part libraries)
How to build and run unit-tests
How to install application
They also allow important tasks like cross compilation and packaging for deploy.
These task done via specific build system scripting language that allow you big flexibility.
So, these build systems generally much more powerful then typical "project files" and they
generally work with multiple compilers on different platforms and operating systems.
Some of build systems (like CMake) allow as one of the options to generate MSVC solutions as well as one of optional ways to build application.

Using Makefile instead of Solution/Project files under Visual Studio (2005)

Does anyone have experience using makefiles for Visual Studio C++ builds (under VS 2005) as opposed to using the project/solution setup. For us, the way that the project/solutions work is not intuitive and leads to configuruation explosion when you are trying to tweak builds with specific compile time flags.
Under Unix, it's pretty easy to set up a makefile that has its default options overridden by user settings (or other configuration setting). But doing these types of things seems difficult in Visual Studio.
By way of example, we have a project that needs to get build for 3 different platforms. Each platform might have several configurations (for example debug, release, and several others). One of my goals on a newly formed project is to have a solution that can have all platform build living together, which makes building and testing code changes easier since you aren't having to open 3 different solutions just to test your code. But visual studio will require 3 * (number of base configurations) configurations. i.e. PC Debug, X360 Debug, PS3 Debug, etc.
It seems like a makefile solution is much better here. Wrapped with some basic batchfiles or scripts, it would be easy to keep the configuration explotion to a minimum and only maintain a small set of files for all of the different builds that we have to do.
However, I have no experience with makefiles under visual studio and would like to know if others have experiences or issues that they can share.
Thanks.
(post edited to mention that these are C++ builds)
I've found some benefits to makefiles with large projects, mainly related to unifying the location of the project settings. It's somewhat easier to manage the list of source files, include paths, preprocessor defines and so on, if they're all in a makefile or other build config file. With multiple configurations, adding an include path means you need to make sure you update every config manually through Visual Studio's fiddly project properties, which can get pretty tedious as a project grows in size.
Projects which use a lot of custom build tools can be easier to manage too, such as if you need to compile pixel / vertex shaders, or code in other languages without native VS support.
You'll still need to have various different project configurations however, since you'll need to differentiate the invocation of the build tool for each config (e.g. passing in different command line options to make).
Immediate downsides that spring to mind:
Slower builds: VS isn't particularly quick at invoking external tools, or even working out whether it needs to build a project in the first place.
Awkward inter-project dependencies: It's fiddly to set up so that a dependee causes the base project to build, and fiddlier to make sure that they get built in the right order. I've had some success getting SCons to do this, but it's always a challenge to get working well.
Loss of some useful IDE features: Edit & Continue being the main one!
In short, you'll spend less time managing your project configurations, but more time coaxing Visual Studio to work properly with it.
Visual studio is being built on top of the MSBuild configurations files. You can consider *proj and *sln files as makefiles. They allow you to fully customize build process.
While it's technically possible, it's not a very friendly solution within Visual Studio. It will be fighting you the entire time.
I recommend you take a look at NAnt. It's a very robust build system where you can do basically anything you need to.
Our NAnt script does this on every build:
Migrate the database to the latest version
Generate C# entities off of the database
Compile every project in our "master" solution
Run all unit tests
Run all integration tests
Additionally, our build server leverages this and adds 1 more task, which is generating Sandcastle documentation.
If you don't like XML, you might also take a look at Rake (ruby), Bake/BooBuildSystem (Boo), or Psake (PowerShell)
You can use nant to build the projects individually thus replacing the solution and have 1 coding solution and no build solutions.
1 thing to keep in mind, is that the solution and csproj files from vs 2005 and up are msbuild scripts. So if you get acquainted with msbuild you might be able to wield the existing files, to make vs easier, and to make your deployment easier.
We have a similar set up as the one you are describing. We support at least 3 different platforms, so the we found that using CMake to mange the different Visual Studio solutions. Set up can be a bit painful, but it pretty much boils down to reading the docs and a couple of tutorials. You should be able to do virtually everything you can do by going to the properties of the projects and the solution.
Not sure if you can have all three platforms builds living together in the same solution, but you can use CruiseControl to take care of your builds, and running your testing scripts as often as needed.