Raylib: [build] Avoid external dependencies

Created on 13 Nov 2017  路  18Comments  路  Source: raysan5/raylib

One of the biggest features for next raylib version is avoiding external dependecies, specifically GLFW3 and OpenAL Soft.

Since the beginning of raylib I tried to make the library as much stand-alone as possible but managing all library parts is quite difficult, so, I had to use some amazing external libraries for different things. Most of those libraries come in the form of single-file header-only libraries that can just be distributed along with raylib... but two of them are bigger libraries that must be compiled per platform-basis and distributed along with raylib for linking... those two libraries are GLFW3 and OpenAL Soft.

Both libraries are great but when dealing with multiple platforms and depending on those libraries could be a pain because linking raylib programs in the different platforms require installing (and sometimes compiling) those libraries independently. That was the situation until now.

One of the objectives for next raylib version is simplifying that situation, to the point of not depending on any external library (I mean, depending only on the basic system libraries for every platform). To get that, GLFW3 will be compiled as an additional raylib module (rglfw) and OpenAL Soft will be replaced by a lightweight alternative (https://github.com/raysan5/raylib/issues/385).

enhancement

Most helpful comment

Personal opinion: im sick and tired of most build systems and have resorted to using mostly sing header library and basic make files. So rglfw and mini-al sound like a great improvement to ease of use!

Do note that I mostly use raylib to get a basic cross platform GUI in c for small personal tools so I may not be the target demographic :smile:

All 18 comments

Instead of depending on the systems libraries or having the user manually link them to CMake, why not just use something like https://hunter.sh/, which is a pure CMake dependency manager. I've been using it for years and it substantially eases these kinds of issues.

An example:

Download the hunter gate file file to, oh, the cmake/HunterGate.cmake in the project (or where-ever you want) first, it is the part you don't need to update, it is the scaffolding for the rest. Then include it into your CMakeLists.txt:

include("cmake/HunterGate.cmake")

In the CMakeLists.txt file for this library you would then add a repository (or multiple) that you want to be able to pull from, the hunter.sh 'standard' repository that contains quite a large amount of package metadata is this example below, it does already include glfw3 and openal:

HunterGate(
    URL "https://github.com/ruslo/hunter/archive/v0.19.154.tar.gz"
    SHA1 "f86a59e0cf169e2d9f765f63708c25628b288c12"
)

There are other options as well, but this is the basics and really is all that is needed for this project.

A repository is just a git (or file or a variety of other supported things) that contains just the metadata needed to know how to acquire, compile, and link in a library, easy enough to create your own, but really not needed for raylib.

Next you should tell it what libraries you want it to depend on (by default it will download these at the precise version specified in the dependency repo you chosen, which is immutable so no sudden upgrade-surprises, but you can override the version if you want, or the user can override the version, or they can tell hunter to use the system libraries only or for specific libraries), so for the current versions (as of the above repository snapshot) of glfw3 and openal you'd add these lines after the HunterGate line:

hunter_add_package(glfw)
hunter_add_package(OpenAL)

Then in the project definition use the normal CMake methods for importing their definitions (nothing special here):

find_package(glfw3 REQUIRED)
find_package(OpenAL CONFIG REQUIRED)

Then just link them as normal:

target_link_libraries(... glfw OpenAL::OpenAL)

Then just build as normal, what happens is:

  1. HunterGate downloads the repository cache to a .hunter directory in $HOME (overrideable by the user, this is what I will refer to as the 'cache' directory here on out, awesome to save on CI work) if it is not already downloaded, and verifies it's SHA1 hash.
  2. It then checks if the wanted packages are already downloaded to the cache, if not it downloads them at the version specified (or the 'stable' version as specified by the used repository).
  3. It then compiles the dependencies using the specified options (or defaults as specified by the repository) using whatever compilation system the dependency requires (you can mix and match cmake and non-cmake projects all you want, the metadata handles this) and it will not recompile unless necessary (like the compile-options change, they are compiled based on a hash of all the compiler options so multiple projects have no conflicts). Sometimes the metadata includes cmake build files for a project, this is the case of glfw3 for example, they do that to make it much easier to use.
  4. Then it sets up the path and location information for the libraries for the CMake-standard find_package to link them in as normal, it is all standard from here.

This makes it so you do not need to create other repositories, that you will always use the same version of glfw3/openal regardless of who compiles it on whatever platform, and overall speeds up builds thanks to it caching everything.

This will still allow this library to be add_subdirectory'd into projects, and/or you can even submit your own metadata to the hunter.sh standard repo (which makes it so users of raylib are just a single hunter_add_package(raylib) away, to add it you just submit a PR to https://github.com/ruslo/hunter for the metadata entry, even linking back to this repository so you can store the metadata here as well to keep things in sync. You can even create your own rayrepo for hunter if you wished as well that just stores what you care about.

Hi @OvermindDL1, thank you very much for your proposal, I didn't know about hunter dependency manager.

But actually, my intention with those changes is just avoid dealing with more package managers and avoid users to deal with that. It adds extra complexity to the library and more tools required to build the sources. Keep in mind that most raylib users are students with no programming experience at all, I try to make things easier for them.

Adding additional complexity to the project building also requires additional maintenance efforts and I don't have enough time for that; even the CMake build implementation for raylib, done by one user, is still uncomplete: https://github.com/raysan5/raylib/issues/336

Removing those only two dependencies could make raylib a standalone library in most of the platforms, as said, with no building dependencies, and that's really my objective.

But actually, my intention with those changes is just avoid dealing with more package managers and avoid users to deal with that. It adds extra complexity to the library and more tools required to build the sources. Keep in mind that most raylib users are students with no programming experience at all, I try to make things easier for them.

Indeed, which is why I think Hunter.sh is useful, it is pure cmake and it is 1 cmake call + 1 cmake call per package to acquire, quite simple.

Adding additional complexity to the project building also requires additional maintenance efforts and I don't have enough time for that; even the CMake build implementation for raylib, done by one user, is still uncomplete: #336

Ah, how is one to build this then otherwise?

Removing those only two dependencies could make raylib a standalone library in most of the platforms, as said, with no building dependencies, and that's really my objective.

Is definitely preferred. ^.^

...it is pure cmake and it is 1 cmake call + 1 cmake call per package to acquire, quite simple.

Actually, it's quite simple... but it requires CMake installed + 2 CMake calls for two packages + 1 CMake for code + 1? CMake for examples + configuring/maintaining all CMake files. For a programmer that's not much, for a non-programmer just trying to play with graphics that's maybe too much...

Ah, how is one to build this then otherwise?

raylib uses a plain Makefile for all platforms building.

Actually, it's quite simple... but it requires CMake installed + 2 CMake calls for two packages + 1 CMake for code + 1? CMake for examples + configuring/maintaining all CMake files. For a programmer that's not much, for a non-programmer just trying to play with graphics that's maybe too much...

It's less work then having them try to get a dependency via their package manager (or worse on windows, manually). ^.^

But if the dependencies are removed, no biggie anymore. :-)

raylib uses a plain Makefile for all platforms building.

Oh that is a simple makefile, could be easily made cmake. Would not matter anyway though, hunter could use this library even via it's makefile system (as long as that works on windows as well, it would need to support the platforms that at least cmake supports), but that is tangential anyway unless wanting the library to be used with an extra cmake command in other cmake projects without needing to manually acquire/build it.

@raysan5 I currently have the same needs in my project as you, regarding GLFW and OpenAL Soft.

Regarding GLFW, I'm working on a cleaner window API (SWFW), that I plan to keep only as a two-files (a source and a header) library. Currently I only have initial support for X11 and Wayland with EGL (it's a pretty recent project), and I want to add support for Windows, Mac OS, WebGL (with Emscripten) and later mobile. I know it's not an immediate solution, but I thought it could be of your interest.

Hi @ferreiradaselva! Thanks for the info! I'll keep an eye on your project!

Right now I'm just including all GLFW in an stand-alone module (rglfw) but probably that solution is not the best one as stated here.

About OpenAL Soft replacement, I'm very confident with mini-al library. Looks really promising!

Personal opinion: im sick and tired of most build systems and have resorted to using mostly sing header library and basic make files. So rglfw and mini-al sound like a great improvement to ease of use!

Do note that I mostly use raylib to get a basic cross platform GUI in c for small personal tools so I may not be the target demographic :smile:

Hi @minecraftlog21, thanks for your point of view, I think the same way, also tired of external dependencies and complex build systems but I'm also concerned that, embedding all GLFW3 modules into rglfw, I'm breaking some basic software engineering good practices. In this specific case, not a big deal but it's probably a bad reference for newcomers.

About your basic GUI system, take a look to raygui, despite not being as complete as I would like, it's functional... I use it for basic tools.

I suggested that GLFW source can be included in binary, but also to leave option, e.g. GLFW_SHARED so Linux distributions can link to glfw lib, they all prefer shared libs of course, and don't like when they need to unbundle something.

Still, I think it is good idea, issues with versions, issues with static/shared lib naming, in many cases user must compile manually GLFW, on Windows binary releases of libraries to link are used etc. Also, like it is now, you have some control over version that is used. I don't agree it bloats binary, binary have exactly what it needs, and will be standalone. So GLFW_BUNDLED being a default, and option for shared library would be nice.

I wait for mini_al changes to lend into develop branch so OpenAL can be removed in raylib-go :)

I suggested that GLFW source can be included in binary, but also to leave option, e.g. GLFW_SHARED so Linux distributions can link to glfw lib, they all prefer shared libs of course, and don't like when they need to unbundle something.

Include the binary is not really a good idea on Linux. If someone has an older version of glibc installed, and the binary was compilled on a newer version of glibc, the binary probably won't work.

@ferreiradaselva The result binary is not a fully static binary (that includes static libc or libstdc++, or libm), so that is not an issue here, it only doesn't link to glfw lib, that are the only bits included.

I like gen2brain's idea of leaving the option to link to glfw3 but also having the option to use rglfw.

Hi @gen2brain, I was about to close this issue when I saw your proposal for GLFW_SHARED, it's a good idea.

I saw GLFW has _GLFW_BUILD_DLL option for shared library but enabling it in rglfw doesn't seem to work for me, everyting compiles fines and runs without asking for glfw3.dll. How are you enabling it?

Hi, I just meant to make some custom option in Makefile, that when enabled links to glfw3 as was before, if not enabled then it uses rglfw (default).

All Linux distributions will prefer that, so if they have some reasons to link to shared glfw3 they can do that without patching. Currently there is also option for static/shared build of raylib, most distros will go with shared option, no matter if there are games in their repo that use raylib or not. So I guess both Makefile and cmake files should have that option, just to be distro friendly (most will probably just use cmake, autotools Makefile is ok, custom made one is not ok, it is usually like that with distros).

Related to issue #401 I can also provide ebuild for Gentoo and i can post it to their bugzilla, maybe also to some overlay and maintain it, I probably need to proxy maintain it (something like that existed before) , but I guess better to wait for 2.0 release before that. In 2.0 it will be clear what dependencies are needed and that there are no external dependencies unless some distro wants it that way.

My intention was enable rglfw to build GLFW as dynamic library, so GLFW shared library would be required... it didn't work for me...

I can just skip rglfw from build on Makefile with a flag, so, linking with external GLFW shared library... but in that situation, we face again the glfw.so vs glfw3.so issue that is dependant on Linux distro.

In the meantime, I would enable USE_EXTERNAL_GLFW flag in raylib source default Makefile and examples.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SethArchambault picture SethArchambault  路  9Comments

Geams picture Geams  路  3Comments

raysan5 picture raysan5  路  12Comments

raysan5 picture raysan5  路  4Comments

Triangle345 picture Triangle345  路  8Comments