2015-02-08 06:34:04 +00:00
|
|
|
First, an introduction is in order:
|
|
|
|
|
|
|
|
Hi, I'm iKarith, and probably you don't know me. :) I'm not really part of
|
|
|
|
any "scene" or anything. Long story short, I wanted to build a stand-alone
|
|
|
|
emulator-based box for my fiancée and thought RetroArch might give her
|
|
|
|
something clean, seamless, and foolproof once I set it up. And as some of
|
|
|
|
you who haven't been big fans of RetroArch may guess, that wasn't easy.
|
|
|
|
|
|
|
|
Two choices existed: Complain, or fix it. I chose to fix it. And when I
|
|
|
|
found out where things were headed for RetroArch, I decided to first see about
|
|
|
|
improving its build process.
|
|
|
|
|
|
|
|
To that end, this file and the files in the repo with "iKarith" in the name
|
|
|
|
were created. They're temporary and will go away once this project's done.
|
|
|
|
This file in particular explains what I'm doing and why. So read on if that
|
|
|
|
stuff interests you. :)
|
|
|
|
|
|
|
|
iKarith, 2015-02-07
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
## History
|
2015-02-08 06:34:04 +00:00
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
2015-02-08.0: Added discussion of dependencies
|
|
|
|
2015-02-07.1: Changed heading levels
|
|
|
|
2015-02-07.0: initial writing
|
|
|
|
|
|
|
|
## Some philosophy
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
Libretro should be an API, not a project. You might want to argue with me as
|
|
|
|
to whether or not that's true. And you might be surprised to find me agree
|
|
|
|
that as of today, it *is* a project and not an API. But that model is IMO not
|
|
|
|
infinitely sustainable. You can't just fork every open source game project
|
|
|
|
out there.
|
|
|
|
|
|
|
|
You can't even do that with all the emulators. And even if you could, it'd be
|
|
|
|
a nightmare trying to compile them all, let alone maintain them. And it's
|
|
|
|
just not realistic to hand a user a dozen SNES emulators with no explanation
|
|
|
|
of what's what and expect them to know what to do with them all, especially
|
|
|
|
since there are multiple versions of some of them. Now multiply that by all
|
|
|
|
of the systems and all of the emulator engines and all of the versions of some
|
|
|
|
of them that exist. It just does not scale.
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
### The technical problem
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
Leaving aside the philosophical direction of where libretro is headed for a
|
|
|
|
moment, its build scripts don't really function well for where the project is
|
|
|
|
at today, let alone in the future when it's "not really a project" anymore.
|
|
|
|
|
|
|
|
You see, libretro does not have one build script. In fact, it doesn't even
|
|
|
|
have one build script per target platform. No, there's the combination of
|
|
|
|
libretro-fetch.sh, libretro-build.sh, and retroarch-build.sh and their
|
|
|
|
included subscript dependencies. In addition, there's about a dozen or so
|
|
|
|
platform-specific build scripts which have some overlap with the main scripts
|
|
|
|
and (inconsistently) use their dependent subscripts. In addition, there's a
|
|
|
|
handful of XCode projects for Mac OS X which are intended to be backward
|
|
|
|
compatible with old versions of the OS but aren't. And there's a whole
|
|
|
|
additional set of build scripts replacing most of these almost in their
|
|
|
|
entirety written for the buildbot. And then there's the Makefiles which
|
|
|
|
are often just as much of a mess (but a separate problem…)
|
|
|
|
|
|
|
|
This is why the iKarith-\*.sh scripts. If you touch any of the mainline
|
|
|
|
scripts to do what we need to do, you *will* break something. In fact, I
|
|
|
|
happen to know that most of the scripts need a (fairly trivial) patch as it
|
|
|
|
is. Mea culpa for introducing the need, but those scripts that don't get
|
|
|
|
patched before I get to them are the ones I can assume may have suffered other
|
|
|
|
forms of bit rot and will require additional care/testing.
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
### The Political Problem?
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
As I said, I don't really know anybody. So I can't pretend to understand all
|
|
|
|
of the issues involved with devs in the various "scenes" in question. I know
|
|
|
|
some people feel that they should retain control of their projects. I have
|
|
|
|
seen someone accuse libretro of trying to "steal" other projects to improve
|
|
|
|
their own. There are probably other issues, some of them personal, and I just
|
|
|
|
don't know them. And I don't need to, honestly.
|
|
|
|
|
|
|
|
What I can say is that what I have in mind for the new build system makes
|
|
|
|
libretro-super function kind of like Debian/Ubuntu's package system. You give
|
|
|
|
it the equivalent of an apt sources.list entry and it should be able to
|
|
|
|
download your project from your site, build it for your system, package it,
|
|
|
|
and possibly even give you the means to upload it to a repository.
|
|
|
|
|
|
|
|
My own future interests involve building a standalone libretro player for a
|
|
|
|
single project so that you can build something that targets the API and
|
|
|
|
distribute it as a stand-alone game, and a small version of SDL that's built
|
|
|
|
for libretro so that SDL-based games could be compiled for use on lakka.TV
|
|
|
|
down the line. Remember what I said I originally wanted to accomplish?
|
|
|
|
|
|
|
|
I don't know if any of this stuff will help or hinder resolution of any
|
|
|
|
outstanding issues between anyone. I'm just here to make cool stuff easy
|
|
|
|
enough for my fiancée to use it, remember? :)
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
## Dependencies
|
|
|
|
|
|
|
|
For all the discussion of "no external dependencies", libretro and the stuff
|
|
|
|
ported to it have a lot of them. That's unavoidable, actually. To simplify
|
|
|
|
the argument, let's presume a GNU/Linux build environment. You can't compile
|
|
|
|
anything without a compiler and binutils. And the only way you're going to
|
|
|
|
compile large batches of code is a dependency on make. Those are obvious.
|
|
|
|
|
|
|
|
|
|
|
|
### The less obvious dependencies
|
|
|
|
|
|
|
|
Continuing with our Linux example, all make does is give you a way to specify
|
|
|
|
what commands are required to create/update a file, and what files it is
|
|
|
|
created from. From there, the commands are executed in a shell, which
|
|
|
|
introduces a dependency on the shell, but also the shell commands. Things
|
|
|
|
like echo and cp are not traditionally "builtins", but rather external
|
|
|
|
programs that were traditionally smaller than the ELF header required to tell
|
|
|
|
Linux how to run them. (And old enough versions of Linux didn't use ELF…)
|
|
|
|
|
|
|
|
By this point you've got literally 500MB of dependencies on a modern Linux
|
|
|
|
system. You could argue that some of that is irrelevant because classically
|
|
|
|
all of the above fit into 50MB on a Linux system dating back to a 1.x kernel
|
|
|
|
and the fact that the dependencies have bloated so much (largely for UTF-8,
|
|
|
|
translation, internationalization, etc.) isn't our problem. That's fair
|
|
|
|
enough, but we still have a minimum of 50MB of build dependencies on Linux.
|
|
|
|
|
|
|
|
Add the build scripts in there and you add dependencies on git (which means
|
|
|
|
also perl and possibly python though nothing we do requires anything that uses
|
|
|
|
python until you try to build mame at least) and explicitly on bash. I'm
|
|
|
|
pretty sure our current build scripts will run on bash 2.05 at least, but most
|
|
|
|
folks assume bash 4 is available on all systems these days. (It's not—the Mac
|
|
|
|
still comes with bash 3.)
|
|
|
|
|
|
|
|
If we remove the bash dependency, we could claim a POSIX environment as a
|
|
|
|
build dependency, but notably some platforms are not and do not even pretend
|
|
|
|
to be POSIX, such as that little insignificant OS called Windows. You could
|
|
|
|
install MSYS (or more likely MSYS2) to try and fake it at the shell script
|
|
|
|
level, but MSYS2 is one *significant* dependency.
|
|
|
|
|
|
|
|
This is why autoconf exists. It's also why autoconf is the gigantic mess
|
|
|
|
(both in terms of size and ugly complexity) that it is: It cannot assume a
|
|
|
|
fully POSIX system, and the POSIX standard is pretty dated anyway. It has to
|
|
|
|
figure out all of the quirks of UNIX-style (and non-UNIX) systems running on 8
|
|
|
|
bit processors that haven't been updated in 35 years or more.
|
|
|
|
|
|
|
|
|
|
|
|
### So, what's your point?
|
|
|
|
|
|
|
|
The point is that we cannot say that we have no, or even few build
|
|
|
|
dependencies. And at present, the ones we do have are not declared. Fixing
|
|
|
|
this can be done in three ways, two of which aren't really worthwhile:
|
|
|
|
|
|
|
|
1. We can use autoconf. In addition to all the reasons why this idea just
|
|
|
|
sucks, the fact is that it won't solve our problem anyway because some
|
|
|
|
cores have build dependencies, even if they should be free of external
|
|
|
|
runtime dependencies. Not only that, we cannot easily predict if down the
|
|
|
|
line you want to use libretro-super to build a core out of a mercurial or
|
|
|
|
subversion repository.
|
|
|
|
|
|
|
|
2. We could try to reinvent autoconf for our purposes. This has the advantage
|
|
|
|
that we could build a system that accommodates our build system's needs and
|
|
|
|
also provides a means for cores to declare additional build dependencies if
|
|
|
|
they need them. It has the obvious disadvantage that no attempt to replace
|
|
|
|
autoconf has ever really been successful for a reason. Either you have to
|
|
|
|
introduce an external dependency (as cmake did) or you have to mix a bunch
|
|
|
|
of 1970s-era script syntaxes like autoconf does because they're the only
|
|
|
|
ones you can guarantee are installed everywhere.
|
|
|
|
|
|
|
|
3. We can simply state our dependencies from the outset and expect the user of
|
|
|
|
libretro-super to meet them. We may have to jump through a few hoops to
|
|
|
|
deal with where things are installed. For example, our scripts might be
|
|
|
|
best run using the same /usr/bin/env tactic used by Python developers to
|
|
|
|
avoid hard-coding a path that isn't portable.
|
|
|
|
|
|
|
|
This doesn't solve the core build dependency issue by itself, but it does
|
|
|
|
assure that if the libretro-super user has installed the prerequisites for
|
|
|
|
using libretro-super, we CAN solve that problem without resorting to the
|
|
|
|
kind of abomination that is autoconf.
|
|
|
|
|
|
|
|
Obviously I see but one choice here. However care needs to be exercised still
|
|
|
|
to ensure that our libretro-super dependencies are in fact __reasonable__. I
|
|
|
|
would love to be able to take advantage of modern versions of bash, for
|
|
|
|
example, but Mac OS X users don't have it unless they installed it themselves.
|
|
|
|
It's not even guaranteed with MacPorts or Fink installed, so it's a different
|
|
|
|
issue than on Windows where people are going to have to install something no
|
|
|
|
matter what we use.
|
|
|
|
|
|
|
|
|
|
|
|
## The solution so far
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
To begin with, let's talk about the proof of concept I have already
|
|
|
|
implemented. Then we'll discuss where it goes from here. For this discussion
|
|
|
|
we will use the 2048 project because it's an incredibly simple example. In
|
|
|
|
fact it's just about as close to a functional "hello world" for libretro as I
|
|
|
|
can imagine. Currently it fetches and compiles using these rules:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
fetch_libretro_2048() {
|
|
|
|
fetch_git "$REPO_BASE/libretro/libretro-2048.git" "libretro-2048" "libretro/2048"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_libretro_2048() {
|
|
|
|
build_libretro_generic_makefile "2048" "." "Makefile.libretro" ${FORMAT_COMPILER_TARGET}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
What happens if we take the information contained there and turn it into a
|
|
|
|
bunch of shell variables that describe what to do with "2048":
|
|
|
|
|
|
|
|
```bash
|
|
|
|
core_2048_dir="libretro-2048"
|
|
|
|
core_2048_fetch=fetch_git
|
|
|
|
core_2048_source="$REPO_BASE/libretro/libretro-2048.git"
|
|
|
|
core_2048_build_rule=build_libretro_generic_makefile_s
|
|
|
|
core_2048_makefile="Makefile.libretro"
|
|
|
|
core_2048_other_args="$FORMAT_COMPILER_TARGET"
|
|
|
|
```
|
|
|
|
|
|
|
|
You'll notice that the build subdir is not specified—it's implicit. You'd
|
|
|
|
only have to set the variable if you needed to specify one. If the project
|
|
|
|
used ``makefile`` or ``Makefile`` to build for libretro, you wouldn't need to
|
|
|
|
specify that either. And actually, so much of the above "core definition"
|
|
|
|
uses what would be reasonable defaults, you really only need to specify the
|
|
|
|
``core_2048_source`` and ``core_2048_makefile`` lines. The rest could be
|
|
|
|
totally implicit, but I never really got that far before I had to attend to
|
|
|
|
other things.
|
|
|
|
|
|
|
|
But the info doesn't have to be specified in shell variable format. In fact
|
|
|
|
it's not actually that difficult given bash to actually parse a file like
|
|
|
|
this:
|
|
|
|
|
|
|
|
```ini
|
|
|
|
[2048]
|
|
|
|
source = "https://github.com/libretro/libretro-2048.git"
|
|
|
|
makefile = "Makefile.libretro"
|
|
|
|
```
|
|
|
|
|
|
|
|
or even
|
|
|
|
|
|
|
|
```ini
|
|
|
|
display_name = "2048"
|
|
|
|
authors = "Gabriele Cirulli"
|
|
|
|
supported_extensions = ""
|
|
|
|
corename = "2048"
|
|
|
|
categories = "Game"
|
|
|
|
systemname = "2048 game clone"
|
|
|
|
license = "GPLv3"
|
|
|
|
permissions = ""
|
|
|
|
display_version = "1.0"
|
|
|
|
supports_no_game = "true"
|
|
|
|
source = "https://github.com/libretro/libretro-2048.git"
|
|
|
|
makefile = "Makefile.libretro"
|
|
|
|
```
|
|
|
|
|
|
|
|
Yes, the .info file could contain instructions for compiling. Not useful to
|
|
|
|
RetroArch in the least, but useful if the .info file becomes the basis of a
|
|
|
|
package description. Which is kind of what I have in mind.
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
### Still needed
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
The FORMAT_COMPILER_TARGET variable and FORMAT_COMPILER_TARGET_ALT are
|
|
|
|
extremely simple. They are kind of used to specify which compiler toolchain
|
|
|
|
to use, but the settings are defined, redefined, or overridden in about four
|
|
|
|
or five different places including sometimes the cores' Makefile! And on my
|
|
|
|
system, it is simply "osx". I have two versions of gcc and a Clang available
|
|
|
|
here, and I can build code for any of 8 architectures, two of which my system
|
|
|
|
can also actually run. And the only configuration of my compiler is "osx"?
|
|
|
|
|
|
|
|
Let's start by defining my system with a system and a native architecture.
|
|
|
|
We'll use MacOSX-x86_64. And I have multiple compiler toolchains available.
|
|
|
|
Let's assume that libretro-super identifies Clang and the gcc version that
|
|
|
|
runs as ``/usr/bin/gcc``. Both build for MacOSX-x86_64, so I would wind up
|
|
|
|
having two compiler profiles.
|
|
|
|
|
|
|
|
If a core can't build with Clang, its build recipes might specify a preference
|
|
|
|
for gcc if there are choices, or even indicate a conflict with Clang older
|
|
|
|
than whatever version is current if we ever get around to implementing that
|
|
|
|
kind of thing. If it can't build with my system, it should be skipped by
|
|
|
|
default unless explicitly requested otherwise.
|
|
|
|
|
|
|
|
Those cores like 2048 that build as universal binaries might say that on
|
|
|
|
MacOSX-x86_64 and MacOSX-i386 it prefers MacOSX-Intel which would be a fat
|
|
|
|
binary for both. Those kinds of overrides are why the existing info file may
|
|
|
|
NOT be suitable for specifying all the build rules, even if most of them are
|
|
|
|
implicit.
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
### External sources
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
This stuff is still a work in progress in my head (even more than compiler
|
|
|
|
profiles by target), but here we go.
|
|
|
|
|
|
|
|
Let's say the [SuperTux](http://supertux.lethargik.org/) project wants to
|
|
|
|
target libretro. Awesome, right? All they would have to do is publish a link
|
|
|
|
somewhere. I'll make one up for the purpose of running:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
./libretro-super.sh add-repo http://supertux.lethargik.org/libretro
|
|
|
|
```
|
|
|
|
|
|
|
|
Update the repo list to make sure I have the build rules and I should be able
|
|
|
|
to just do something like this:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
./libretro-super.sh auto-package supertux/SuperTux
|
|
|
|
```
|
|
|
|
|
|
|
|
This would perform all steps to build a packaged version of SuperTux for my
|
|
|
|
system, which in this case requires a full fetch, build, and package.
|
|
|
|
|
|
|
|
The package likely named ``supertux_libretro_MacOSX-x86_64.zip`` would
|
|
|
|
contain:
|
|
|
|
|
|
|
|
```
|
|
|
|
supertux_libretro.dylib
|
|
|
|
supertux_libretro.info
|
|
|
|
COPYING_v3.txt
|
|
|
|
README-libretro.txt
|
|
|
|
```
|
|
|
|
|
|
|
|
The file README-libretro.txt would be a simple blurb that this version of the
|
|
|
|
game is built as a plugin for a libretro player and directs you to the
|
|
|
|
SuperTux website and to information about what a libretro player is and where
|
|
|
|
you'd find one.
|
|
|
|
|
|
|
|
You'll note I adopt the Windows and frankly everything but CLI UNIX convention
|
|
|
|
of adding an extension to COPYING. I also chose to give it a version
|
|
|
|
designation.
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
## Porting features
|
2015-02-08 06:34:04 +00:00
|
|
|
|
|
|
|
Porting features from the iKarith scripts to the standard scripts is fine,
|
|
|
|
indeed it's welcome. Just keep in mind that while it's possible to do, you
|
|
|
|
really need to test everything you can if you do. At the very least, make
|
|
|
|
sure that you test Linux, Windows, and OS X if possible. You might also want
|
|
|
|
to check with radius as to whether or not your changes will break his
|
|
|
|
buildbot.
|
|
|
|
|
|
|
|
That's about all I can think of for now. This file will see updates as the
|
|
|
|
concepts contained herein evolve.
|
|
|
|
|
|
|
|
|
2015-02-08 10:12:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
<!-- vim: set tw=78 ts=8 sw=8 noet ft=markdown spell: -->
|