Transmission torrent client ported to C++
github.com
github.com
It's complicated but it's the only reasonable choice. You can then write your code C-style while compiling it as C++ and nobody will bat an eye.
Very practical and reasonable choice.
Unless you use anything that pulls in locale code (e.g. any stream), in which case you will get code for things like date and monetary formatting in your library even if it is never used.
Personally, I was impressed by an approach taken by the authors of Pixie (a fast 2d library like Cairo) [2]. They created a "library wrapper" generator for Nim code that supports creating libraries Python, Node, C, and Nim itself that they call Genny [3]. Haven't tried it but being able to use Nim and it's ref based gc but still export to nice API's in other languages is fantastic. Pixie's aim is to be a Cairo alternative so it makes sense they'd need this. I hope the approach takes off. Usually writing any cross language API's is a lossy operation.
Here's a sample of the API definition:
exportObject Matrix3:
constructor:
matrix3
procs:
mul(Matrix3, Matrix3)
1: https://dlang.org/spec/betterc.html
2: https://github.com/treeform/pixie
3: https://github.com/treeform/genny(edited formatting)
Notice that betterC does not exclude templates or destructors, so you could still use c++-style containers based around RAII, etc.
The argument against it is a smaller ecosystem and you’d end up having to roll your own containers etc.
You mean "Das C" ? :)
I understand the historical context that lead to the creation of Glib (no C++ standard in the mid-'90s, no decent open Objective-C libraries, Stallman and most of the FOSS movement at the time harbouring a deep disgust towards C++ for some reason, etc), but it can't be pointed at as a good example of how to code in C - on the contrary, it's IMHO exactly what your C project shouldn't do. You've picked C because it's simple and clear, don't butcher it up with macros and weird hacks just to get a worse Objective-C.
Well, yeah, that was 23 years ago. Back then there was no GNUstep and no free as in freedom C++ or Objective-C compiler. Now GCC's main development language is C++ and GNOME is slowly becoming somewhat language agnostic and also has Vala which at one point was supposed to cover up that mess.
I guess another point is that they seem happy with it[1], so why should we care anyway.
G++ was available in 1990. I don't recall when Objective C became available in GCC, but it was present in at least gcc-2.2.2 in 1992.
I think that Glib was born from the same mentality which considered C as the perfect language, with the end goal of getting the same functionalities of modern languages without leaving it.
But yes, you're right, they could have developed Glib in either of those languages even if STL and *step didn't exist yet. I also found this e-mail[1] from Stallman that supports your claim. Do you know of more documentation? I'm interested in this history.
Here is one of the original versions of the GNU Coding Standards from 1994,
https://www.schwedler.com/old/HTML/standards_7.html#SEC12
> Using a language other than C is like using a non-standard feature: it will cause trouble for users. Even if GCC supports the other language, users may find it inconvenient to have to install the compiler for that other language in order to build your program. So please write in C.
https://web.archive.org/web/20041029162424/https://www.gnu.o...
As you can see, it basically consisted in "use C, unless you _really_ have too". It was also well known that C++ was heavily discouraged by Richard Stallman, so picking it could well end up in your project having a hard time being adopted by GNU.
The guidelines were relaxed afterwards, especially since GCC came to rely on C++ and every relevant C compiler was then written in C++, making the whole "we don't want to force people to install g++" even more nonsensical. In 2004 C++ was already way too ubiquitous to not have g++ installed.
In fact, if “fast” is the most important requirement we'll probably write it in Fortran or C++. With C++ you just have to know which parts not to use.
[1] Fortran Web Framework https://news.ycombinator.com/item?id=28509333
I'd reach for abseil first: <https://abseil.io/>.
Edit: I originally linked to the wrong video (https://www.youtube.com/watch?v=TFMKjL38xAI), which was a different talk by the same person.
Hence why I keep my C and C++ skills sharp, even though they aren't my main languages any longer.
In addition to having experts accidentally make mistakes with `ref ref` like in that first video that resulted in performance degradation due to unwanted copies, C/C++ is a major security risk. Countless vulns are from simple mistakes and complex misunderstanding.
So even though managed languages and better systems programming languages are making their replacements, somewhere down the stack there will be C++.
And then to top it, as long as people insist in using UNIX clones, C will be there as well.
Some good points, but also "calling find with C strings is slow", you are using C strings, don't expect speed from code worshiping strlen of all things. Also the issue with integer hash being its identity? That is the case for every language I checked (Python, Java, C#).
The mindset behind C++ is not a relative "thing must be good enough", but an absolute "there must not be something better possible".
Of course, this is often not realized in practice, but it's the goal.
It maps all integer values to distinct hashes which seems rather ideal, what it doesn't give you is perfect performance in an artificial benchmark written to exploit this implementation.
everything that's old and has legacy is doomed to have several. It's just a fact of life.
The C++ committee doesn't and can't just throw away stuff like `std::vector<bool>`, despite it being a whole fractal of bad ideas, because people have already used that piece of dung in uncountable projects. It would be nice to have a way to get a _normal_ vector of booleans (even though vector<char> just suffices most of the time), but that's life I guess.
[1]: <https://news.ycombinator.com/item?id=28098153>
But back to the point, my original comment wasn't about C++ being a bad choice. It was about STL. You can use C++ without STL. I pointed to one alternative: abseil.
Also, C++ hasn't features like built-in move semantics and borrow checking, so it's very hard to enforce certain things that just come natural in Rust. That's simply stating a fact. The real point here is that std::optional<T> is much less likely to cause UB than a plain, old C pointer, so it's a net improvement - even though it could still lead to UB in some circumstances.
Every language has its pitfalls and I tend to prefer C++ pitfalls to some other pitfalls. Lately I having been doing some python. Turns out a python -m venv is different from a virtualenv. Turns out pytest some/specific/test/file.py is different from python -m pytest some/specific/test/file.py. I am wishing quite hard this code base consisted of all C++. And of course mypying this is still on the TODO list so the type annotations that are there might well lie.
Exceptions will propagate up the stack, but won't clean up resources since the C code expects to do that manually. Same is true for non-RAII C++ code that is not written to expect exceptions.
Your main point is correct though: Large parts of the C++ stdlib do not throw.
I think it's more to glib development entering an ice age, than a language issue.
Glib had an impressive roadmap list around 8-10 years ago, copying much of STL features, but of course nothing much materialised after GNOME 3 caused an exodus of GTK developers.
Any C program can be converted to build with a C++ compiler with no more than a day's work. Then, you can start in modernizing the active parts, deleting local, generally poorly-tested, cobbled-together utilities as you go.
> This PR is the first incremental step of getting libtransmission to compile with a C++ compiler.
It connects to less peers when downloading or uploading.
Why do people still use C then? In what aspects is it better than C++? Is C++ less portable than C?.
apt install transmission-cliFor torrents, I tend to just use rtorrent, which has worked perfectly for me for probably 15 years now. https://github.com/rakshasa/rtorrent. Nice, fast, doesn't seem to use many resources to get the job done.
https://trac.transmissionbt.com/browser/branches for pre-2016
https://github.com/transmissionbt from 2016
When we untar the source, the "Changelog" file is empty
diff -U0 -r transmission-2.94 transmission-3.00|less
Look for compelling reasons to updateWhen statically compiled 2.94, stripped binaries were 3.4M; not too bad
Still had to make fixes by hand to get it to compile with musl. These were reported by a musl user on Github years ago. Oh well
Need to include bsdqueue.h instead of sys/queue.h in these two files
third-party/miniupnp/portlistingparse.h
third-party/miniupnp/upnpreplyparse.h
Needed to fix some libcurl problem in libtransmission/web.c, toohttps://trac.transmissionbt.com/ticket/5580
The need for web.c is debatable; "webseed" is not peer-to-peer, who even uses it
Wonder if its even worth the effort: https://trac.transmissionbt.com/log/trunk/libtransmission/we... "pulling my hair out"
1.
https://web.archive.org/web/20111005094923/http://download-o...
https://web.archive.org/web/20160726015340/http://download-o...
Might have miscounted but looks something like
Year Releases
2006 6
2007 8
2008 19
2009 50
2010 21
2011 10
2012 11
2013 7
2014 2
2015 0
2016 1 +
2017 0
2018 2
+ In 2016 started using GithubWould be nice if there was a compile-time option to disable the BEP 17 BEP 19 feature
And on another project, it was great to be able to use std::map instead of rolling my own equivalent. The only thing that scares me is exceptions.
"Zero cost abstractions" are, in practice, quite rare.
Unfortunately I no longer remember in which conference he did it, maybe someone else can link it.
If you don't believe me, read what Linus Torvalds has to say about why the Linux kernel is built with -Os by default.
EDIT: This is the talk, if I remember correctly.
https://isocpp.org/blog/2018/06/cppcon-2017-going-nowhere-fa...
But the main problem with -Os is that it is poorly exercised. The best-exercised modes are -O0 and -O2, so those are the ones to use in production.
Err... yeah, because -Os means "optimize size". Not "speed".
> But the main problem with -Os is that it is poorly exercised
No, the main problem is that you don't understand -Os :) It works as intended.
And, that any compiler feature that is little used will necessarily receive less attention than commonly used features, and be less stable and reliable. Before trying to fix any bug in a program built with -Os, reproducing it first in -O2 will reduce premature balding.
I have no idea what you're talking about. Debug your programs in -O0, which means "no optimizations". -Os is, and has always been, optimizing for executable SIZE. It has no guarantees wrt performance.
At -O2 the assembly it generates is straightforward, and in line with what a human programmer would write. At -O3 it generates vector code that needs a lot more instructions (vector pipeline setup, code to deal with the remaining elements that don't entirely fill up a vector register, etc.) but the main loop takes 4 integers at a time instead of one, so that provides a nice 4x speedup. In order to achieve that it needs 25 instructions to set up the loop / finish the remaining elements, compared to 5 instructions for the -O2 code.
For very short loops the -O2 version will have superior performance, but for runs of data from around 8 integers (wild guess) the -O3 version will begin with pull ahead. So it really depends on the type of data your program is handling, whether it is better to optimize for speed or size.
The size of the stripped binaries should be compared. ELF binaries contain both link-time sections and loadable segments, and the longer name of C++ symbols only affects disk space (for both the link-time symbol table and for debug information). The size of the runtime-loadable segments is really the only thing of interest, and stripping the binaries gives you a truer indication of this.
-rwxr-xr-x. 1 rjones rjones 4167912 Sep 12 22:09 build-c++/gtk/transmission-gtk
-rwxr-xr-x. 1 rjones rjones 3997408 Sep 12 22:12 build-c/gtk/transmission-gtk
-rwxr-xr-x. 1 rjones rjones 3130352 Sep 12 22:09 build-c++/daemon/transmission-daemon
-rwxr-xr-x. 1 rjones rjones 2959640 Sep 12 22:12 build-c/daemon/transmission-daemon
build-c++/utils/:
total 12156
drwxr-xr-x. 6 rjones rjones 4096 Sep 12 22:08 CMakeFiles
-rw-r--r--. 1 rjones rjones 5653 Sep 12 22:08 cmake_install.cmake
-rw-r--r--. 1 rjones rjones 289 Sep 12 22:08 CTestTestfile.cmake
-rw-r--r--. 1 rjones rjones 13793 Sep 12 22:08 Makefile
-rwxr-xr-x. 1 rjones rjones 3082448 Sep 12 22:09 transmission-create
-rwxr-xr-x. 1 rjones rjones 3066256 Sep 12 22:09 transmission-edit
-rwxr-xr-x. 1 rjones rjones 3182928 Sep 12 22:09 transmission-remote
-rwxr-xr-x. 1 rjones rjones 3073952 Sep 12 22:09 transmission-show
build-c/utils/:
total 11496
drwxr-xr-x. 6 rjones rjones 4096 Sep 12 22:12 CMakeFiles
-rw-r--r--. 1 rjones rjones 5645 Sep 12 22:12 cmake_install.cmake
-rw-r--r--. 1 rjones rjones 287 Sep 12 22:12 CTestTestfile.cmake
-rw-r--r--. 1 rjones rjones 13725 Sep 12 22:12 Makefile
-rwxr-xr-x. 1 rjones rjones 2917136 Sep 12 22:12 transmission-create
-rwxr-xr-x. 1 rjones rjones 2895128 Sep 12 22:12 transmission-edit
-rwxr-xr-x. 1 rjones rjones 3014872 Sep 12 22:12 transmission-remote
-rwxr-xr-x. 1 rjones rjones 2901832 Sep 12 22:12 transmission-show...and people wonder why software gets slower and bigger over time while doing the same thing. We even get HN articles about that semi-regularly.
Pretty much everything else in the C++ standard library is template code in headers and gets instantiated when needed. You may end up having identical templated functions emitted into several different translation units and the linker will chose one at link time, which is one major reason why C++ is slower to build.
Only template functions that are actually used get instantiated. If you include a header with a gazillion templated functions (namespace level or member functions, it doesn't matter) you are most likely to end up with only one or two instantiated in your binary. Templates are like a cookbook, and just because Larousse has 10,000 recipes does not mean that's how much you're going to eat at every meal. Consider there is virtually an infinite number of possible instantiations for every template.
Edit: libcxx from Chromium, not libstdc++
https://github.com/microsoft/vscode/pull/129360#issue-952350...
> The increase in bundle size is significantly small (~10MB).
That's not material.
The amount of increase is irrelevant if it continues in the same direction.
And it's "optimize for size", by the way.
Test the two with Release instead. That will give you real results.
text data bss dec hex filename
920576 11508 4152 936236 e492c build-c++/gtk/transmission-gtk
912575 11644 4120 928339 e2a53 build-c/gtk/transmission-gtkkthxbye ;)
For 99% of cases, regex-replace is the better choice (as much fun as writing syntax tree transformations is).
Hopefully the refactor ( which has been talked about and planned for many years ) will fix some performance issues. I constantly get 20-30% CPU usage just downloading.
https://transmissionbt.com/download/
Although, I'm more amazed this post has been up an hour without any rust comments..
That said, there are definitely downsides here. Even if they manage to keep c++ entirely out of headers, consumers now have the headache of either building libtransmission themselves _or_ making sure they include a compatible runtime in their own projects.
As soon as c++ leaks out into the public interfaces, it's game over for precompiled binaries - everyone will have to build it whether they want to or not. Not the end of the world, but certainly it could be painful for downstream projects.
But agreed this is the right first step.
The rest can be (hopefully) increasingly migrated.
This was both the plus (and now Achilles's heel regarding fixing C++) of migrating C code into C++.
There are more comments on any given post about hypothetical obnoxious Rust comments than any actual comments of that nature.
I've actually thought "WTF why porting a project to a memory unsafe language", but actually the PR title is somewhat excessive - it's more of a modernization, indeed described by the author as "the first incremental step of getting libtransmission to compile with a C++ compiler".
Because proper handling of memory is actually quite easy to achieve in C++ assuming you're doing all the right things. We also have great tooling for this a la sanitizers and valgrind.
Also, C and C++ remain to be more performant than Rust in the general case, and don't require rewriting everything into a completely different paradigm.
That being said I've been using transmission for years without complaints, so I trust them to do the right thing.
Also it seems like the author is already well-versed in C++; learning Rust might not be a priority for them, and would certainly slow things down a lot.
And while there are certainly plenty of footguns and unsafe things you can do in C++ (even unintentionally), it's probably still safer than C, even if it's not as safe as Rust.
If I want to shoot myself in the foot I should have full rights and the ability to do so.
In a normal coding however modern C++ is very reasonable language and I do not recall stepping onto any landmines in a last few years even though my code runs high load / high performance business servers that also do a lot of calculations.
It is quite easy to steer clear of unsafe constructs, and is less work. The people who trigger footguns are mostly those trying to code as if they were still coding C. Their code is typically slower, too.
Perfect programmers don't exist. Everyone will screw up sometimes.
With Rust, I know that my code will be free of memory errors and data races as long as I never use `unsafe`. No one can say the same about a C++ program, not with certainty.
If you don't care, that's fine (I guess), but please don't get all huffy with those of us who do. I think it's telling that you seemed to need to get all defensive even considering that my original post was in support of the libtransmission author using C++ instead of Rust.
Formal proof is a thing, so I think you can.
"Hello world" would be easy to verify. Verifying transmission on the other hand, is a kind of big project on its own, though.
And I agree, that there are no perfect programmers around, but I would also agree to parents point, that if I want to have full power, I fully want to remain my right for footguns. It all remains a tradeof. The ecosystem of C++ is just incredibly bigger than rust, so a new game, I would start in C++, but for something critical I would probably also choose rust.
A piece of code without memory errors is, by definition, memory safe. This whole idea of "every piece of code has bugs" is some new-wave tripe coming out of code camps and the web development scene.
Still, that all would be predicated on having good Rust experience or using it as a learning experience and that may not be the motivation of the authors.
Is this realistically possible on a non-trivial project? I suppose that porting to safe Rust requires a radical rearchitecture of the code.
So almost unavoidably you end up with two refactors: first, the piecemeal rewrite in the the safer language, and then a second when the original language has been rooted out and you can take advantage of all of the features of the new language.
Are there any practical torrent clients that I can run in docker container?
Do you have any real example that you been bitten by such conversion?
> but I don't think GP deserved the downvotes for the speculation.
That's why I asked @squid_demon for a real example that possibly got bitten by it; else, it's simply an emotional reaction for favoring one tool over another.
If aria2 [1] that is implemented in C++ is extremely fast, then I can almost guarantee that transmission's refactoring in C++ will get there too, sooner or later.
https://lordsoftech.com/programming/error-codes-are-far-slow...
Maybe that author should use a profiler before making these types of claims? check the generated assembly? etc?
Far slower to return a value in RAX vs. generate a ton of code (blowing icache, etc.) is quite an interesting statement. I think it deserves a closer look, though.
The only case where a string is returned in the exception-based code is Xml::getAttribute() where in both implementations there is exactly one copy (copy assingment in the error code case and copy construction in the exception case).
Being able to just return the type in the good case is however one of the main advantages of using exceptions, so it might even be valid to count such optimizations being possible in more code as a plus of using exceptions.
> Maybe that author should use a profiler before making these types of claims? check the generated assembly? etc?
Have you used a profiler before making your claims?
> Far slower to return a value in RAX vs. generate a ton of code (blowing icache, etc.) is quite an interesting statement. I think it deserves a closer look, though.
The cost for error codes is the branching at every point in the call stack vs. only at the error source with exceptions. And the generated exception code is marked as cold and not stored interspersed with the non-exception code so will not affect performance unless exceptions are thrown - which if you are usng exceptions correctly should be exceptional cases.
Maybe the dude forgot to enable optimizations altogether (not present in the command line options in the comment at the top of that file). I added /O2 since it is a PERFORMANCE test, remember? Hilarious.
The primary reason people use C today is extreme portability.