Building Distributable Linux Binaries?
Grubby Games asks: "I make games for a living, and I want to ensure that my games will run on as many Linux distros as possible. However, since I distribute binary game executables, the programs often fail to run on certain distros because of missing dependencies, and so forth. So, how do the Slashdot Linux gurus handle this situation? I've heard a number of theories on the subject, but have yet to find one that results in 100% cross-distro compatibility. Is it even possible, short of distributing source code?"
How many comments until someone asks "Why not distribute the source?"?
Ah geeks..always finding a way to answer the question with a better(?) one.
Turkey.
Java and Python are obvious. You can always use things like JNI and the Python-C bridge if you feel you need better speed in some parts. As long as those parts don't link to any external code, you won't have any problem. They are both very fast these days, and by using things like PyOpenGL and Java3D you can get accelerated rendering and everything. Plus you would only need one codebase for both windows, linux, and OS X.
As for a static build, you may or may not want to do that. The size of the executable will be much larger, and it will take more memory to run, but you won't have the problem of everyone has a different version. It would solve your problem.
As an odd suggestion: why not build all your code into objects and distribute those with a little script to link them on the client machine into an executable. That would fix the problem right? The problem is you couldn't strip the binary (if you do that) because the linker needs the symbols (right?). But it would solve you problem. This is my understanding of how nVidia's kernel drivers work (they have a little glue source too, which you could include). This way they don't have to put out a version for every combination under the sun.
I hope this helps. This is one area where Linux is (rather far) behind Windows and OS X. It's not much of a problem if you've got the source, but if the application is closed source (like yours) then it can be a headache. This is something that the LSB was trying to solve, but I don't know how far they got (or how many distros follow their guidelines).
Comment forecast: Bits of genius surrounded by a sea of mediocrity.
It can't be done with dynamic linking, despite what the Autopackage people tell you. There's too much variety between distributions with things like libc and libstdc++ versions. There's even too much variety between distribution releases in many cases.
Most distributions don't aim to provide binary compatibility between releases. Even RedHat get sick of shipping multiple copies of libraries eventually... And if you throw distributions like Gentoo into the mix, anything binary-based using dynamic linking is out of the question.
If you really must distribute binaries, static link them and distribute the associated libraries too. Assuming, of course, that said libraries' licences don't prohibit this -- for open things you're fine, but for obnoxiously licenced code (like your own) you're short of luck. Also note that you can't legally do this with LGPLed libraries (nor GPLed, of course).
*shrug* Of course, any respectable Linux user won't use your software unless they can see the code anyway. How else do we know it's not chock full of security holes and spyware?
- statically link everything
- do not expect any file to be in a given place
Though you could create a live cd based on knoppix with only what you need and distribute that.
actually, they look entertaining.
a hardcore gamer might not want to play them, but for casual gamers, they look like they could be quite fun (if they're done properly).
I believe UT2K4 achieves this by including the libraries themselves in one of the application's directories. Just link to the ones you place in the applications directory as opposed to system libraries and you are all set. Correct me if I am wrong, which is entirely possible.
Not the only way, there is also statifier
From the page:
Statifier create from dynamically linked executables and all it's libraries one file. This file can be copied and run on another machine without need to drag all it's libraries.
I have noticed that applications compiled for glibc 2.1.3 run on systems with glibc 2.3.1, but not the reverse. You can find glibc 2.1.3 and gcc 2.95 on Slackware 7.1.
Netscape 4.8 and Maple 5.0 have been compiled for libc5 and run on many systems.
I meant that applications compiled for glibc 2.1.3 run on systems with glibc 2.3.4. I have not tried 2.3.1.
I have been building binaries on Redhat7.2 which seem to work OK on Fedora Core 3 (with compat-libstdc++, except there have been some problems when exceptions are thrown - anyone know anything about this?) - I assume they work OK on distributions in between too.
Does anyone know how to build binaries on newer distributions that run on older ones, especially ones that use C++. Stuff compiled on fc3 seems to link to linux-gate.so, which I guess is not going to go down too well on the older distros.
If you're making games, it's usually a good solution to make the game engine open source, and charge for the data. The game engine can get ported to dog knows what platforms without any effort from you, and you can still get compensated by charging for the data files. The real value of a game tends to be in the data files, as they control the story line, the graphics, the sound effects, basically everything. The game engine is just like a library used to play the datafiles. Of course, not all games work like this.
Please correct me if I got my facts wrong.
If you absolutely can't have the source to your app open, you could do like the developers of binary kernel modules: ship your software in object format, with all the parts that interface with the rest of the system open source. That way, people can't read your actual application source, but they can compile and link the glue layer to make your code work on their system.
If you take this approach, be _very_ careful to have _everything_ that interfaces with the outside system in the open source part; I've worked with kernel modules where some OS calls were still made from inside the binary part, and they were hell.
Please correct me if I got my facts wrong.
I'd suggest doing a bootable CD. You can have total control, then. In my limited experience, gamers are typically not too disturbed by having to do a reboot to get to their game.
http://tinyurl.com/4ny52
``100% cross-distro compatibility. Is it even possible''
In a word, no. Binary compatibility just isn't. It happens to work in very select situations, usually on proprietary operating systems that are themselves binary-only, which means the developers of the OS would be dealing with the same headaches you would if they broke binary compatibility.
On Linux, where binary compatibility has very low priority because _everything_ on the system works fine without it, binary compatibility happens only by accident. It starts with the fact that Linux runs on many architectures, and people actually use it on most, if not all, of these architectures.
Then there are distributions that are still using libc5. Think they don't matter? What happens when libc7 comes out? And if you think that isn't going to happen for a long time, how about when X.org replaces the monolithic structure they inherited from XFree86 by their new, modular one? Or how about when Qt 4 replaces Qt 3, or GNOME 3 is released? These projects are not going to let themselves held back because of your app. Because this is what binary compatibility means: slowing progress, because some changes become impossible.
Please correct me if I got my facts wrong.
Static Linking. It results in bigger bloated binaries - but at least they're self-contained.
You make the mistake of thinking you can educate the fundamental stupidity out of people. You can't.
You might want to take a look at klik:
http://klik.atekon.de/
If you just link the stuff statically, you shouldn't have much trouble.
I would probably set up an apt repository for Debian, where it's easy to make sure it works with the given dependencies. I would complement that with a statically linked rpm and plain old tarball.
Well, in actual fact I would also distribute it as FOSS, of course. I doubt that would impact your revenue negatively. Rather, the fact that people have the possibility to patch bugs and port it themselves would probably make them more willing to shell out for it in the first place. There's few things as frustrating as broken software that you know you could fix, but the creator won't let you.
distribute your game as a chroot'able .dd.tar.gz file ..
; -- the corruption of government starts with its secrets. a truly free people keep no secrets. --
Mike
"Not an actor, but he plays one on TV."
Visit the Game Programming Wiki!
Static: Ah nice big pile of .a's or in Win .LIB, internet? wooz that
.LT. deltaOPPS) THEN
Dynamic RTL : WEEEEEEEEEEEEEEEEEEE I just rely on $env, luck and def-alt
THINKS
Put the whole sheebang in and RDMS/SQL thing hidden even from uber-admin; viz Prog A calls proc Z in Lib G ver 1.2.3.4.5.6.7.8 mean while MEGA BIG HDD provides space for all libs ver 1.2.X up to 2.0.1.z
Anything missing is XMLed/RSSed to the server(s) which contained said lib (obv. RTL)
If only someone like SUN could think that up, maybe replace those 1.2.3.x with say a DNS style address...
Oh and regression testing is a breeze, or do I mean wind/gale/typhoon?
STOP programing, LEARN libs, STOP LEARN LIBS, FLUSH, RE-LEARN LIBS
IF (OPPS
LIBS == CLASS
ELSE
java
END IF
{where LIBS & CLASS are submembers of CODE}
You can do a few different options, each with their own drawbacks. Depending on the libraries you are currently using you will possibly have to use a combination of these items.
Static linking allows you to distribute a single binary that will run on any linux system so long as you have the correct minimum kernel version and CPU. Some of the problems with this will include the license on the libraries you are using may not allow this, and the application's code image changes from what you have debugged against.
Dynamic linking and putting all of the required dynamic libraries your application requires in their own personal library directory. This is the quickest solution, but not always the best solution. It does allow you to release periodic incremental patches to the binaries used by your applicaton.
Usage of a application such as Elf Statifier to take your debugged dynamic application, and bundling the applicable libraries into your application. This is a halfway point between a completely dynamic and static application that allows you to take your "GOLD" release and package it up without changing the generated code in your application.
Just release your application as a dynamic application and mark it with the correct dependancies in RPM format and follow the Linux Standards Base.
Most commercial applications will use either the 2nd method (dynamic and distribute all their own versions of various dynamic libraries) or the 4th method. In both cases they specify a message to the effect of "We support X distro version Y. It may work on your linux distro, but we only support X version Y."
As you are planning to make money off of this game, I wish you luck, and suggest you take a look into what the most popular linux distros for your target audience will be. Based on advertisements from Wal-Mart and Fry's selling Linux preloaded I would bet Linspire and Xandros is high on that list. As with all things, don't forget the testing across many distributions to make sure the solution you choose actually works.
The program isn't debugged until the last user is dead.
I saw blah blah blah distro, so fun idea, why not make the necessary libraries for running the application available, and then run the program in a self contained box (chroot jail?) for distros that wont work with said game?
Distributors who want to make it hard for you to run your binaries are every bit as wise as the Unix vendors who tried to avoid standardization and the risk of mutual success...
--dave
davecb@spamcop.net
autopackage is probably the current best tool for this. It makes a single, easily installable (and removable) package while coercing my system's GCC and libs into versions that are suitable for other distributions.
:)
I use it currently for schism tracker (particularly the CVS builds that I do).
It works very well for me: Debian, Ubuntu, SUSE, Fedora, Gentoo, and Mandrake users have reported success with these binaries built with (gasp) a lone FC4 machine.
One day, I'll actually do a proper release and six years later it'll show up in the next Debian release. Then your fancy apt-get tools will work.
And to kneejerk jackasses that say "just release the source"- you must realize that the source is good for you and me (well me anyway, I cannot speak for you, obviously), the people who USE these programs have absolutely NO INTEREST in doing the work that I have just done for my own purposes.
Plus, having them use a single binary means that it's very easy to debug with nothing more than a core file.
Oh, and I suppose I am giving the submitter the benefit of the doubt that we are indeed talking about Free Software, aren't we?
Many distrobutions = Good, (more competition, more innovation).
HOWEVER, the catch is that the answer to the above question is not a unanimous "Yes, here's how and it'll work for most if not all distrobutions." Why? Too many variables to account for. To be almost universal across the linux distro, you'd have to release at least three different binarys (which at most covers a dozen or so of the most common distros). To make it completly universal across all linux distros, you'd have to release your source codes and provide detailed instructions to compile for some of the more difficult distrobutions AND be prepared to make adjustments and help people with new flavors of linux every day.
How many times have I found a reasonably popular piece of software for linux, and been detered by a compile process that was either too complicated (and undocumented) or that produced a binary that just didn't work. I personally shy away from any software that has to be compiled unless I REALLY want it. Sure, two times out of three it moves along painlessly, but when there's a problem it can sometimes be a *badword* to figure out. How many times have I found a great looking linux application only to discover that they dont release ANYTHING for my distrobution and maybe only even for some obscure distro. It's a pain in the hindquarters.
Alternativly, you could release your games online in flash. I realise that isn't the BEST business model and that it's NOT universal across all platforms, but you have a standard that works for a large number of Linux distrobutions AND Mac AND Windows.
We need a single standard for software under linux... and a full-featured set of libraries to go with it. Whereby if a coder chooses to write for all linux platforms he'll know that if it works for one, it'll work for everyone who complies with the standards and keeps their libraries up-to-date. If that coder chooses to code specifically for some special feature found only in one or two distros, so be it... but at least the divide wont HAVE to be there.
This was the idea behind Java. Have you looked into using that?
As someone who is involved in supporting commerical closed-source applications on 3 Windozes, 5 Linuxes and 4 Solarises, I must confess - binary compatibility on Linux is too damn hard.
Solaris is way better than Linux in that regard, everything compiled on lower versions always works like a breeze on higher versions. Windows has a clear dividing line between retarded 95/98/ME and 2000/XP/2003/Vista, but we do not support 95/98/ME anyway, so binary compatibiity on Windows is wonderful, aside from some minor glitches with missing DLLs.
Now, binary compatibility on Linux is a total pain in the butt. Incompatibilities in glibc 2.2 vs 2.3, pthreads vs nptl, gcc C++ ABI is broken on every other gcc release, thread local storage, just to name a few hurdles.
Distributing statically linked executables is the most reliable way to go, if you want to support as many Linux variants as possible. However, there are few things to remember:
* If your application is security-critical, you link against static library and later security flaw is found in the library, OS security update leaves your application vulnerable.
* Never link statically with libdl. For example, application, statically linked on RH 7.3 witl libdl will misteriously crash on RH9
* Size of executables is big. Even worse if you have many executables using same libraries.
Oh, you said you are going to market games... Boy, you are better to build them for Windows anyway. Don't let me be misunderstood, I love Linux (except, for its binary (in)compatibility, of course), but it's just not the right market and business model for you anyway.
If you keep insisting on Linux, here is a hint. Most commercial vendors shipping products for Linux are oriented towards a limited number of distros, those used in enterprises. RedHat and SuSE that is. Mandriva? Ha-ha-ha. Oh, you say, Ubuntu and Debian are popular? Ouch, not among our cutomers.
my sstream of consciousness
Dude, all you have to do is build a static binary that doesn't need any outside files, and program it so that the only thing outside of your program that you depend on are system calls that have been around since, say, kernel 2.4 or so. Then, you're just about guaranteed that your software will work on any system. In fact, if you use system calls that are pretty much available on any *nix, then you're pretty much guaranteed that it will work on anything with an x86.
Java on the other hand is Java. Unless you want to go the SWT route, if you are using Swing/Java2D, all the stuff is there.
Distribute all the shared libs you need, except for glibc. (BSD licensed, right?) Link all your binaries (including shared libs) against an older glibc version, and it will be forward-compatible with newer glibc versions, thanks to versioned symbols.
This pretty much guarantees compatibility across distributions. Just make sure the glibc you link against is old enough. Then just distribute binary tarballs and tell people only "glibc 2.2 or newer required" "glibc 2.3 or newer required" etc. It works pretty well.
-molo
Using your sig line to advertise for friends is lame.
We (my company) use a disk image from Redhat 6 to compile binaries. Old versions of gcc, X, gtk etc. The programs work fine on everything new. GCC/Gtk/QT all need to do a feature freeze for programs to work in all distros IMHO. I might suggest to also looking at the loki installer. It works on new and old Linux systems.
Enjoy,
It's just the normal noises in here.
Gamers shouldn't condescend so much to the casual gaming market, and certainly not their developers. These guys are living the dream, after all (and realizing the dream means coding down in the trenches). Power to you, Linux-supporting casual gamer guy.
Help poke pirates in the eyepatch, arr.
For regular binaries, a static build is pretty much guaranteed to work. Alternatively, all Linux distributions I know of do honor the LD_LIBRARY_PATH environment variable. Create a library directory on the target computer, then test the libraries already installed. If the ones you want are either not there or the wrong version, copy the ones you have on the CD into the library directory and have that directory searched BEFORE the default system library directories.
If using custom versions of standard libraries, use a chroot jail to guarantee that the program cannot see the regular library directories.
If you don't actually need standard functions at all, but use your own routines and maybe some system calls, then there's absolutely no problem - just remember that when you compile, you want to PREVENT GCC from linking in the C library. Rescue tools, installers and other components that have to run PRIOR to being able to check versions, etc, should either be statically linked OR not linked at all.
If you want to avoid including stuff that might not be necessary, then you can use yet another technique. Write a "loader" program and include that as source. All the loader does is dlopen() the application (which is now written as a shared library, not an executable) and start it up.
This technique works by linking to the installed libraries in the wrapper, and then when you dlopen() the application, the application can then access the linked libraries. The linking is entirely done in the wrapper, which would always be compiled for the local system.
This technique would only work if all the required libraries are present, and the parts of the API that are used are present and the same. If you write to the libraries which are damn-near universal, then this will work. If you are writing to libraries which are not universal, then you would still have to do the whole process of checking and installing your own libraries, then setting the LD_LIBRARY_PATH. In which case, don't bother with the wrapper and just do that for all libraries.
A final option is to provide TWO programs. The first program assumes nothing about the native system and doesn't do any checks at all. It just installs everything it needs in local directories, sets all the paths as needed, and runs in its own corner.
The second program would be a clean-up program. It has a list of applications it knows about, what versions of what libraries are needed, etc. It would pull libraries that are not system-wide into a standard set of directories, then use symlinks or LD_LIBRARY_PATH to repoint applications to where the libraries are. It would also need two additional capabilities - deinstalling libraries when NO application still installed uses it, and updating records (and shuffling links as needed) when an application is updated.
The reason for the second program is that many developers (especially commercial vendors) have the same problem. If a standardized mechanism existed for library tracking, with a well-known API, I believe it would become very popular very quickly. If such a program were developed, and was sufficiently widely adopted, you could abandon system-wide libraries altogether. Which would be no bad thing, as the existing system has problems with multiple versions and will also fail when libraries have the same filename. It's also slow when you've a lot of libraries installed.
By creating virtual directories, in which the ONLY libraries present are ALL that the application needs, you eliminate not only the application/library issue, but al
It's a small world and it smells funny; I'd buy another if it wasn't for the money; Take back what I paid (SoM)
I think his best option is to distribute packages for various common distros, and a few statically-linked tarballs for everything else. Another thing that comes to mind is CPU optimizations; I don't know if he's thuoght of this, but is he distributing generic 80386-compatible packages, or things designed to run on MMX or 3dNow! chips?
Kermit and distributed.net are examples of places where you can almost always find a binary for your system. Those might not be bad places to look to figure out what sorts of binaries people actually find themselves needing. You're right---there aren't going to be millions of Ubuntu users out there, but for those that are there, static linking might be okay. It's true that security fixes in shared libraries aren't going to fix the same flaws in statically linked binaries, but if someone is using a non-mainstream distribution, they're more likely to be more security-conscious anyway, and probably will only run binaries they didn't compile themselves under special UIDs or chroot jails, so it's probably not a big issue.
Automagically-obfuscated source code is always an option, although remember it's only obfuscation, so if someone figures out your secrets, you're out of luck. Of course, obfuscated source code isn't that much different from assembled code, sicne you can always disassemble/reverse-engineer binaries to get some form of obfuscated source...
--TheOrangeSquid Is it any wonder things seem so awry? We swim in a sea of confusion and don't have to think to survive
It depends what sort of games you are writing, but if not graphics intensive, you could package the game+all essentials on a lightweight linux distro, and put the whole thing out as a virtual machine using VMWare Player.
Humorous signatures are over-rated.
The parent may be completely wrong, but it's certainly not trolling. The post provides a perfectly viable and logical explanation of the point it is making about binary compatibility.
Just because you (or I) don't think that the explanation is likely doesn't make it a bad post. And it's certainly not a troll (ie. done for effect) by any stretch of the imagination.
Go easy on the troll key. In this case it was totally misapplied.
I do distribute source but i'd like to distribute binaries as well since building from source isn't what everybody likes. E.g. I've made a simple sample code for the Tor GUI contest (http://wyoguide.sf.net/index.php?page=tormgr.html ) but to build it from the source, to get an idea how it works, isn't easy for everybody.
O. Wyss
See http://wyoguide.sf.net/papers/Cross-platform.html
Package your software into an LSB RPM. Anyone (using an LSB compliant distribution) can then install it.
:) And it works pretty well.
If you are using libraries that the LSB does not specify, build private copies and distribute them in your package.
Good lord! That's pretty much exactly how software distribution works on Windows!
Whatever happened to the good old days before dynamic libraries?
We used to link EVERYTHING static and we had a stand-alone binary.
I miss the old days...we've got the resources for it...multi gig RAM, multi-multi gig hard disks, etc.
Yeah, but how much of these libraries do you need for a game?
You mean Linux still has DLL hell? MS solved that with COM.
you might also want to think about making it work on linux on powerpc, amd64, sparc etc.
Call those games? Jeez, you could have done that simple stuff in java.
whether or not you like thier installer/package system you would be pretty mad not to check out thier developer tools.
another option is to build on the oldest distro you plan to target.
in any case there are two main issues with building distributable linux binaries
1: glibc symbol versioning
glibc uses a symbol versioning system that means builds made against a newer glibc not work with an older one.
2: macros in headers. e.g. if you use gtk 2.4 headers then your binary will end up relying on new gtk 2.4 features even if you don't use them in your own code.
both can be solved with some effort i don't know of the details myself but i know autopackages developer tools have found ways to solve the problems with many common libraries.
also if you use C++ libraries (like qt) there are abi issues which basically force you to ship more than one binary. i belive autopackage has recently gained the ability to build multiple binaries for such apps at once and then select the appropriate one at install time.
note: i'm known as plugwash most places but i screwd up registering that here somehow in the past and now can't register
nuff said. the reality is dynamic linking causes more problems than it solves. the argument about it saving space is 'blah' (i.e. true but irrelevant).
Since when is gaming all about eye candy? Commander Keen is still a ton of fun to this very day. It'd be nice if Id or Apogee were to update those games with newer graphics, but that wouldn't make the game any more fun. Heck once in a while I boot up C64 games in VICE and a lot of games for the commie blow away nearly any modern PC or PS2 games for pure fun and playability, even with its lowly 2bpp graphics.
The Christian Right is Neither (Christian nor right). See: Matthew 23, Matthew 25, Ezekiel 16:48-50
A minimally necessary step is to label interfaces with what revision of what standard they use. The distributor then adds interfaces labeled "POSIX 20.3.6" (an imaginary standard) when the 3.6 release comes out. They don't remove the 20.2 stuff until no-one uses it any more (e.g., when they switch from 32 to 64-bit), and ELF apps link to the version they need.
If an application needs a newer version than 20.2, the user can download the newest version from the distributor and have all the versions up to and including 20.3.6.
If, on the other hand, the app needs 20.2.19, it's already there.
And, by the way, the number of down-rev functions needed in libc or the other system libraries is diminishingly small, as standards don;t change very much. Variability is usually seen in application libraries.
The next, optional, steps can be found at MIT, in the documents about CTSS, ITS and Multics: this problem was solved long before Unix saw the light of day.
--dave
davecb@spamcop.net
Linux solved this problem by changing the software distribution model from being customer centric to being distribution centric. I.E. Customer gets software from distribution who compiles and configures software from source. The problem with commercial apps is that they want to bypass the Linux model and use the Windows model where: Distributions are configured similarly enough so that the same app runs on all versions. Companies that want to run commercial software succesfully under Linux on machines running multiple apps: Oracle, DB2, cross-over, OEA products... work with distributions not directly with customers for configuration.
An option that nobody seems to have come up with yet is to use Mono. Yep, it's reverse-engineered "MS crap", but it's actually really good. C# is a nice language to develop in.
Assuming you *can* switch to Mono (and that's a really big "if" there), you could supply instructions for how to install Mono at your Web site for the common distros - it's simple for all Debian-based distros and for Gentoo, and probably RedHat/Mandriva/etc. as well. Alternately, you could (possibly|probably) ship Mono with your code, in something broadly similar to a statically-linked binary.
A big advantage of using Mono would be if you decide you want to ship to Windows users as well - it could be as simple as changing your UI code.
Not guaranteeing that it's a good solution for you, but it might be.
- write your program
- run script to:
- scan for required stubs
- all custom lib code copied to custom dir and procnames renamed to xxx_callname.
- glue layer library created where callname -> xxx_callname
- compile custom lib
- compile glue layer
- compile your program, link it to glue layer
- distribute program binary, source code to the glue layer, the code for the custom library, and a script to check dependency for the glue layer.
- the user then runs dependency check script and compiles only missing lib calls and links to those available when the glue layer is compiled
advantagesThis allows you to avoid the GNU licence problems as you only link to your glue layer library.
You make it simple for the user to compile all required library code as you distribute everything and avoid the possibility of missing librarys.
You still have the advantage of shared library
embedded linux
"I make games for a living, and I want to ensure that my games will run on as many Linux distros as possible."
Are you saying that you make a living making games for Linux? Its a great OS and gaining support every day, but I find it hard to believe anyone is making a living creating games for it. I can see making a living creating games for PDAs or cell phones, but not for Linux PCs today. Perhaps in 5 years it will be possible, but not today. Its good someone is out there making games and trying, but making a living?
Ninjas don't carry tic tacs
I've heard about this problem, but I don't recall whether it is due to a bug in glibc, or a bug in Redhat's many modifications. I just know I haven't run into any such problem in Slackware. I don't even touch Redhat anymore given so many issues like this.
Maybe you should do a survey of your Linux customers and find out exactly why they chose the distribution they are using. I'll bet the answer mostly turns out to be things like "more applications support it". Then you'll see the circular argument. Suffice it to say, if more software makers supported a platform like Slackware or Ubuntu, then more people would choose it. When more people choose it, your market for that version enlarges. There will be other reasons for choosing something like Redhat, such that's what the CEO first heard of.
Then take the subset of cases where the decision of which distribution was left up to a technical person who has lots of experience, and you'll find a wider, and better, variety.
now we need to go OSS in diesel cars