#1313 Clarification regarding packaging games in /usr/games
Opened 2 years ago by eclipseo. Modified 2 years ago

Hello folks,

I am helping a newcomer for packaging and he is packaging a game called stepmania : https://git.sr.ht/~xdbob/rpm-packages/tree/master/item/stepmania/stepmania.spec

This game installs itself in /usr/games and requires that the binary be in the same directory of its data.

Is this conform with Fedora Guidelines? AFAIK /usr/games is part of FHS, but I didn't find info regarding the location of the binary files.

The only doc I've found was from an old page from the Games SIG: https://fedoraproject.org/wiki/SIGs/Games/Packaging

Thanks for your feedback.


I'm not sure even with following FHS guidance for games we can have game data in /usr/games.

Can the game be patched to support traditional FHS load paths? For Lugaru, for example, there's a SYSTEM_INSTALL option that sets a build-time define to embed the correct data directory in the executable.

You can see how it works here: https://gitlab.com/osslugaru/lugaru/-/blob/7f71daa62e89dae1567e999ea34586a6b4d74ead/CMakeLists.txt?ref_type=heads#L311-327

We could install in %{_datadir}/%{name} but the binary should then be in %{_datadir}/%{name}. If it is in %{_bindir}, it fails to load assets:

stepmania

//////////////////////////////////////////////////////
Exception: Couldn't find 'Songs'
//////////////////////////////////////////////////////

Error: Couldn't find 'Songs'

Fixing it involve lots of patching, not sure if it will be fully functioning:

From 42efa3378f473209fb084428c78ff01baab2da0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Robert-Andr=C3=A9=20Mauchin?= <zebob.m@gmail.com>
Date: Sat, 14 Oct 2023 22:52:15 +0200
Subject: [PATCH] Split data, libraries and binary and try to respect the FHS
 on Linux

---
 src/CMakeLists.txt                           | 30 ++++++++++++++----
 src/RageFileManager.cpp                      | 11 +++++--
 src/RageFileManager.h                        |  6 ++--
 src/arch/ArchHooks/ArchHooks.h               |  4 +--
 src/arch/ArchHooks/ArchHooks_MacOSX.mm       | 10 +++---
 src/arch/ArchHooks/ArchHooks_Unix.cpp        | 32 ++++++++++----------
 src/arch/ArchHooks/ArchHooks_Unix.h          |  6 ++--
 src/arch/LoadingWindow/LoadingWindow_Gtk.cpp |  2 +-
 src/config.in.h                              |  4 +++
 9 files changed, 68 insertions(+), 37 deletions(-)
 create mode 100644 src/config.in.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index feea706abd..866b9d7765 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,9 @@ endif()
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})

 # Main project is below.
+if(UNIX OR LINUX)
+include(GNUInstallDirs)
+endif()

 include(CMakeData-arch.cmake)
 include(CMakeData-rage.cmake)
@@ -514,6 +517,7 @@ else() # Unix / Linux
 endif()

 target_link_libraries("${SM_EXE_NAME}" ${SMDATA_LINK_LIB})
+target_include_directories("${SM_EXE_NAME}" PRIVATE ${CMAKE_BINARY_DIR})

 list(APPEND SM_INCLUDE_DIRS
   ${CMAKE_CURRENT_SOURCE_DIR}
@@ -600,12 +604,26 @@ endif()

 target_include_directories("${SM_EXE_NAME}" PUBLIC ${SM_INCLUDE_DIRS})

-if(WIN32)
-  set(SM_INSTALL_DESTINATION ".")
-else()
-  set(SM_INSTALL_DESTINATION "stepmania-5.0")
+if (NOT DEFINED SM_INSTALL_DESTINATION)
+  if(WIN32)
+    set(SM_INSTALL_DESTINATION "." CACHE PATH "Installation directory")
+  elseif(APPLE)
+    set(SM_INSTALL_DESTINATION "stepmania-5.0" CACHE PATH "Installation directory")
+  else()
+    set(SM_INSTALL_DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/stepmania" CACHE PATH "Installation directory")
+  endif()
 endif()

+if (NOT DEFINED SM_LIBDIR_DESTINATION)
+  if(UNIX OR LINUX)
+    set(SM_LIBDIR_DESTINATION "${CMAKE_INSTALL_LIBDIR}/stepmania" CACHE PATH "Libraries directory")
+  else()
+    set(SM_LIBDIR_DESTINATION "${SM_INSTALL_DESTINATION}" CACHE PATH "Libraries directory")
+  endif()
+endif()
+
+configure_file(config.in.h "${CMAKE_BINARY_DIR}/config.h" @ONLY)
+
 if(NOT APPLE)
   if(WIN32)
     set(SM_FULL_INSTALLATION_PATH_LIST "${SM_INSTALL_DESTINATION}" "Program")
@@ -626,10 +644,10 @@ if(NOT APPLE)
     #   install(FILES "${SM_WINDOW_DLL}" DESTINATION "${SM_INSTALL_DESTINATION}")
     # endforeach()
   else()
-    install(TARGETS "${SM_EXE_NAME}" DESTINATION "${SM_INSTALL_DESTINATION}")
+    install(TARGETS "${SM_EXE_NAME}" DESTINATION "${CMAKE_INSTALL_BINDIR}")
   endif()
   if (UNIX OR LINUX)
-    install(FILES "${SM_ROOT_DIR}/GtkModule.so" LIBRARY DESTINATION "${SM_INSTALL_DESTINATION}" OPTIONAL)
+    install(FILES "${SM_ROOT_DIR}/GtkModule.so" LIBRARY DESTINATION "${SM_LIBDIR_DESTINATION}" OPTIONAL)
   endif()
   install(DIRECTORY "${SM_ROOT_DIR}/Announcers" DESTINATION "${SM_INSTALL_DESTINATION}")
   install(DIRECTORY "${SM_ROOT_DIR}/BGAnimations" DESTINATION "${SM_INSTALL_DESTINATION}")
diff --git a/src/RageFileManager.cpp b/src/RageFileManager.cpp
index 84e175e415..fb09df5e88 100644
--- a/src/RageFileManager.cpp
+++ b/src/RageFileManager.cpp
@@ -1,3 +1,4 @@
+#include "config.h"
 #include "global.h"
 #include "RageFileManager.h"
 #include "RageFileDriver.h"
@@ -25,6 +26,8 @@ static RageEvent *g_Mutex;

 RString RageFileManagerUtil::sInitialWorkingDirectory;
 RString RageFileManagerUtil::sDirOfExecutable;
+RString RageFileManagerUtil::sDirOfData;
+RString RageFileManagerUtil::sDirOfLibraries;

 struct LoadedDriver
 {
@@ -279,6 +282,8 @@ static void ChangeToDirOfExecutable( const RString &argv0 )
 {
    RageFileManagerUtil::sInitialWorkingDirectory = GetCwd();
    RageFileManagerUtil::sDirOfExecutable = GetDirOfExecutable( argv0 );
+   RageFileManagerUtil::sDirOfData = SM_INSTALL_DESTINATION;
+   RageFileManagerUtil::sDirOfLibraries = SM_LIBDIR_DESTINATION;

    /* Set the CWD.  Any effects of this is platform-specific; most files are read and
     * written through RageFile.  See also RageFileManager::RageFileManager. */
@@ -328,12 +335,12 @@ RageFileManager::RageFileManager( const RString &argv0 )

 void RageFileManager::MountInitialFilesystems()
 {
-   HOOKS->MountInitialFilesystems( RageFileManagerUtil::sDirOfExecutable );
+   HOOKS->MountInitialFilesystems( RageFileManagerUtil::sDirOfData );
 }

 void RageFileManager::MountUserFilesystems()
 {
-   HOOKS->MountUserFilesystems( RageFileManagerUtil::sDirOfExecutable );
+   HOOKS->MountUserFilesystems( RageFileManagerUtil::sDirOfData );
 }

 RageFileManager::~RageFileManager()
diff --git a/src/RageFileManager.h b/src/RageFileManager.h
index c6ef53520c..3d5d25e21c 100644
--- a/src/RageFileManager.h
+++ b/src/RageFileManager.h
@@ -5,6 +5,8 @@ namespace RageFileManagerUtil
 {
    extern RString sInitialWorkingDirectory;
    extern RString sDirOfExecutable;
+   extern RString sDirOfData;
+   extern RString sDirOfLibraries;
 }

 class RageFileDriver;
diff --git a/src/arch/ArchHooks/ArchHooks.h b/src/arch/ArchHooks/ArchHooks.h
index d1b6d5fcac..dd1de85271 100644
--- a/src/arch/ArchHooks/ArchHooks.h
+++ b/src/arch/ArchHooks/ArchHooks.h
@@ -89,12 +89,12 @@ public:
    /* 
     * Add file search paths, higher priority first. 
     */
-   static void MountInitialFilesystems( const RString &sDirOfExecutable );
+   static void MountInitialFilesystems( const RString &sDirOfData );

    /* 
     * Add file search paths for user-writable directories. 
     */
-   static void MountUserFilesystems( const RString &sDirOfExecutable );
+   static void MountUserFilesystems( const RString &sDirOfData );

    /*
     * Platform-specific code calls this to indicate focus changes.
diff --git a/src/arch/ArchHooks/ArchHooks_MacOSX.mm b/src/arch/ArchHooks/ArchHooks_MacOSX.mm
index d434b622f1..a9ffd1e180 100644
--- a/src/arch/ArchHooks/ArchHooks_MacOSX.mm
+++ b/src/arch/ArchHooks/ArchHooks_MacOSX.mm
@@ -307,26 +307,26 @@ static void PathForFolderType( char dir[PATH_MAX], OSType folderType )
        FAIL_M( "FSRefMakePath() failed." );
 }

-void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable )
+void ArchHooks::MountInitialFilesystems( const RString &sDirOfData )
 {
    char dir[PATH_MAX];
    CFURLRef dataUrl = CFBundleCopyResourceURL( CFBundleGetMainBundle(), CFSTR("StepMania"), CFSTR("smzip"), NULL );

-   FILEMAN->Mount( "dir", sDirOfExecutable, "/" );
+   FILEMAN->Mount( "dir", sDirOfData, "/" );

    if( dataUrl )
    {
        CFStringRef dataPath = CFURLCopyFileSystemPath( dataUrl, kCFURLPOSIXPathStyle );
        CFStringGetCString( dataPath, dir, PATH_MAX, kCFStringEncodingUTF8 );

-       if( strncmp(sDirOfExecutable, dir, sDirOfExecutable.length()) == 0 )
-           FILEMAN->Mount( "zip", dir + sDirOfExecutable.length(), "/" );
+       if( strncmp(sDirOfData, dir, sDirOfData.length()) == 0 )
+           FILEMAN->Mount( "zip", dir + sDirOfData.length(), "/" );
        CFRelease( dataPath );
        CFRelease( dataUrl );
    }
 }

-void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable )
+void ArchHooks::MountUserFilesystems( const RString &sDirOfData )
 {
    char dir[PATH_MAX];

diff --git a/src/arch/ArchHooks/ArchHooks_Unix.cpp b/src/arch/ArchHooks/ArchHooks_Unix.cpp
index d70ec997b7..85841caad8 100644
--- a/src/arch/ArchHooks/ArchHooks_Unix.cpp
+++ b/src/arch/ArchHooks/ArchHooks_Unix.cpp
@@ -368,7 +368,7 @@ RString ArchHooks_Unix::GetClipboard()
 #include <sys/stat.h>

 static LocalizedString COULDNT_FIND_SONGS( "ArchHooks_Unix", "Couldn't find 'Songs'" );
-void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable )
+void ArchHooks::MountInitialFilesystems( const RString &sDirOfData )
 {
 #if defined(UNIX)
    /* Mount the root filesystem, so we can read files in /proc, /etc, and so on.
@@ -382,10 +382,10 @@ void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable )

    RString Root;
    struct stat st;
-   if( !stat(sDirOfExecutable + "/Packages", &st) && st.st_mode&S_IFDIR )
-       Root = sDirOfExecutable;
-   else if( !stat(sDirOfExecutable + "/Songs", &st) && st.st_mode&S_IFDIR )
-       Root = sDirOfExecutable;
+   if( !stat(sDirOfData + "/Packages", &st) && st.st_mode&S_IFDIR )
+       Root = sDirOfData;
+   else if( !stat(sDirOfData + "/Songs", &st) && st.st_mode&S_IFDIR )
+       Root = sDirOfData;
    else if( !stat(RageFileManagerUtil::sInitialWorkingDirectory + "/Songs", &st) && st.st_mode&S_IFDIR )
        Root = RageFileManagerUtil::sInitialWorkingDirectory;
    else
@@ -394,7 +394,7 @@ void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable )
    FILEMAN->Mount( "dir", Root, "/" );
 }

-void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable )
+void ArchHooks::MountUserFilesystems( const RString &sDirOfData )
 {
    /* Path to write general mutable user data when not Portable
     * Lowercase the PRODUCT_ID; dotfiles and directories are almost always lowercase.
diff --git a/src/arch/ArchHooks/ArchHooks_Unix.h b/src/arch/ArchHooks/ArchHooks_Unix.h
index fc1962f874..47b2baf4eb 100644
--- a/src/arch/ArchHooks/ArchHooks_Unix.h
+++ b/src/arch/ArchHooks/ArchHooks_Unix.h
@@ -12,7 +12,7 @@ public:
    void SetTime( tm newtime );
    int64_t GetMicrosecondsSinceStart();

-   void MountInitialFilesystems( const RString &sDirOfExecutable );
+   void MountInitialFilesystems( const RString &sDirOfData );
    float GetDisplayAspectRatio() { return 4.0f/3; }

    bool GoToURL( RString sUrl );
diff --git a/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp b/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp
index 1931ef007d..5c0a6eac72 100644
--- a/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp
+++ b/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp
@@ -29,7 +29,7 @@ RString LoadingWindow_Gtk::Init()
 {
    ASSERT( Handle == NULL );

-   Handle = dlopen( RageFileManagerUtil::sDirOfExecutable + "/" + "GtkModule.so", RTLD_NOW );
+   Handle = dlopen( RageFileManagerUtil::sDirOfLibraries + "/" + "GtkModule.so", RTLD_NOW );
    if( Handle == NULL )
        return ssprintf( "dlopen(): %s", dlerror() );

diff --git a/src/config.in.h b/src/config.in.h
new file mode 100644
index 0000000000..5201dc3843
--- /dev/null
+++ b/src/config.in.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#define SM_INSTALL_DESTINATION "@CMAKE_INSTALL_PREFIX@/@SM_INSTALL_DESTINATION@"
+#define SM_LIBDIR_DESTINATION "@CMAKE_INSTALL_PREFIX@/@SM_LIBDIR_DESTINATION@"
-- 
2.41.0

Log in to comment on this ticket.

Metadata