Hacker News new | ask | show | jobs
by malkia 3118 days ago
Bazel is what I really like (xoogler here, used it mainly with java+protos, minor python/c++, testing, other things). Similarly - gn (though different internals, easier platform switch, etc.), buck, pants, etc.

In all of these I like the single "BUILD" file per directory, and simple text file explaining dependencies.

Also these tools work awesome when you are in a company, and you have underneath - dozen or more libs, sdks, projects that need to run together.

1 comments

> Also these tools work awesome when you are in a company, and you have underneath - dozen or more libs, sdks, projects that need to run together.

I'm pretty sure it works great then. But for the bigger C/C++ ecosystem the problem is that everyone uses another build system. From Makefiles to Automake, Cmake, Gyp, Scons, Bazel, etc. everything is included. As soon as you try to use dependencies that favor a different format you either have to rewrite their project definition in your format or at least build it as an external subproject and manually add the include directories.

Imho that's one of the biggest weaknesses of C++ that even outweighs language concern for me: It's often lots of work to integrate 3rd party libraries. And because of this there isn't a really great ecosystem of libraries (e.g. compared to Javascript and Java).

There is another big reason why there isn't a great ecosystem.

The C mentality of some devs dragged into C++ world.

Already in the 90's we had very nice high level C++ libraries, that could compete with what Java offered later.

Turbo Vision on MS-DOS, Object Windows Library and Visual Components Library on Windows. All from Borland.

PowerPlant on Mac OS, from Metrowerks.

From Microsoft, we had MFC, which started high level like those ones (originally named Afx), but then the beta testers requested for it to just be a thin layer over Win16 and it was reborn as MFC.

Many of the modern C++ patterns were already possible with those libraries, but the C wisdom made many not use them.

Another modern example is Android NDK, Google writes the code in nice C++ classes, that get exposed as low level C APIs, or have a Java JNI barrier (e.g. Skia).

> ...Google writes the code in nice C++ classes, that get exposed as low level C APIs...

I'm not on the android team, but in general it's easier to maintain reverse-compatibility with C ABIs than with C++ ABIs.

And the plethora of libraries and the modest size of the standard library are part of the problem. Let's say you're writing a C++ library that understands git and lets users develop more complex applications with your libgitxx as a building block. Whose filesystem primitives (file, directory, path, user, etc.) do you use? There's really not a satisfactory answer to that question.

Point being, C ABIs don't have this problem as much. They tend to just pass around ints and char. Maybe there are some structs to pass around, but they tend to be made up of ints, char, etc.

@ Google - most of the projects are linked statically, and all source code is present (possibly very, very few exceptions) at compile time (all open-source packages are recompiled too)...

As such, backward compatibility (binary-wise) is not needed.

Android, Chrome, etc. are another matter - former has an SDK, and I guess you may need that there, but I don't have much experience with it.

True, but if it's my understanding that Google doesn't pursue semantic versioning, at least with C++, partly because it's hard for a human being to understand what C++ changes affect an ABI and which ones don't.
I just noticed an old Github issue has been updated a while ago, and we might start seeing some actual NDK C++ APIs with r17 and later releases.
Before C++17, boost::filesystem, now std::filesystem.

In Android's case, the ABI would be whatever g++, now clang, shipped with NDK support.

Additionally there are ways to implement compatible ABIs in C++.

In any case, they are wrapping the C++ classes already, either via C or Java, so they could offer them as well.

Instead, one needs to write unsafe C code, JNI boilerplate or wrap them again in C++.

The need to standardize things like std::filesystem was my point.

> Additionally there are ways to implement compatible ABIs in C++.

Eh... when even compilation flags affect ABIs, it's hard for a particlar C++ file to have a stable ABI. The same is true in C, of course, but the way C libraries are generally designed, it's simpler to be ABI compatible. In C++, arcane and unexpected things like noexcept specifications (affected by changes in underlying libraries!) can change your ABI.

> Instead, one needs to write unsafe C code, JNI boilerplate or wrap them again in C++.

That's a fair point. There might be reasons they'd do that (SLAs they can afford), but that's a presumption.

> The need to standardize things like std::filesystem was my point.

Which circles back to my statement about "The C mentality of some devs dragged into C++ world.".

Many useful C++ libraries were not standardized in the early days beyond STL, because many thought C++ should be like C where libraries are whatever the OS provides and nothing else.

Which is clearly visible in the decision to have ANSI C and POSIX APIs as two separate standards, although most C compilers try to provide some kind of additional POSIX compatibility, specially visible in non-POSIX OSes.

Thankfully, the ANSI C++ committee realized the mistake and now we are getting a useful set of libraries into the standard.

As for compilation flags, even for C it is only true if all compilers on the platform follow the same ABI.

And you still need to provide all variants anyway (debug, single and multithreaded, hard and soft float, pre-defined pre-processor macros, ...).

C ABI only appears to be simple in OSes that happen to be written in C.

Grated that is the case nowadays with most being UNIX clones, besides Windows and mainframes, but it wasn't always like that.

I remember the pain of trying to mix multiple C compilers back in the 90's.

As update to my rant, I have to be faire to the Android team.

Apparently something related to C++ APIs on the NDK is planned to start appearing with NDR r17 onwards, as per Github issues.

Using another build system might seem like a problem, but at the end of the day - it's a list of .cpp, .h files, some defines and possibly some intermediate steps. These rules, list of files, etc. would tend to change much less in a well established library, hence a convert to another build system would not seem that big of a deal, even if two, or more a supported.

Today, Qt, for example has qmake, cmake, qbs? others?

The bazelment trunk, provides bazel rules for building ~30 libraries, among them: openssl, zlib, v8, folly, boost, and others: https://github.com/bazelment/trunk/tree/master/third_party

At work, I'm heavily vested in using Microsoft's VCPKG for new builds of open source libs, they internally use CMake, but then CMakeLists.txt were not even readily available for some of these projects, and the VCPKG maintainers did them.

At some point, or it may already exist, someone would make a converter from one system to another, lossy possibly. For example it's possible to parse everything you need, correctly from a .sln/.vcxproj usign the MSBuild framework, which is now available everywhere (except the actual .props, .target files, which are Visual Studio specific). But on a machine with the Community version of the compiler, these are free to use (should even work under wine). And since a lot of other build systems target .sln, .vcxproj files, this could in a way be a target for a lot of systems to converge, and from there extract what you want: - List of source, header files. - Separation between projects - Defines for each project. - etc.

It doesn't have to be perfect, but it's possible.

Or maybe from ninja generated files (though not meant to be used that way).

Luckily there is sane way to verify whether alternative build for a project works - simply compile it, and verify whether the produced artifacts are the same, or are close enough (list of produced header files, exported symbols, may go even deeper).

And yes, I do miss the Turbo/Borland Pascal's .TPU files, where no .h file was needed, or Borland C++ simple project file that was just listing line by line the .c files, but back then projects (which I was familiar with) were much smaller, even gcc, the linux kernel and others were much smaller then.

It really doesn't matter what build system other libraries use. If you use CMake, you just need to use `find_package` directives (https://cmake.org/cmake/help/v3.10/manual/cmake-packages.7.h...) to integrate third party libraries (which should be separately installed in the system).

It only seems difficult if you're stuck in the mentality of shipping all your dependencies with your source code and statically linking everything. C and C++ libraries actually care about maintaining API (and usually ABI) compatibility, so you don't have to ensure you have a specific version of dependencies.

Come on, you cannot even link C++ shared libraries from different version of standard library, potentially also compiler. ABI compatibility in C++ does not exist.

In C, you still had incompatibilities between compilers. (MS fastcall convention and declspec come to mind...)

There's better ABI compatibility than in the languages where you have to rebuild after every minor version bump. The C++ standard library version (and to some extent, the compiler) should be considered part of the platform.