Merge pull request #1247 from colobot/dev-basedir
Add support for binary relocationmodernize-cmake-1
commit
5815db4062
|
@ -198,7 +198,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|||
add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG)
|
||||
|
||||
# Needed for Debug information (it's set to "No" by default for some reason)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /NODEFAULTLIB:MSVCRTD /NODEFAULTLIB:LIBCMT")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
|
||||
else()
|
||||
message(FATAL_ERROR "Your C++ compiler doesn't seem to be supported.")
|
||||
|
@ -230,7 +230,10 @@ option(DEV_BUILD "Enable development build (enables some debugging tools, local
|
|||
# PLEASE DO NOT USE ON UNOFFICIAL BUILDS. Thanks.
|
||||
option(OFFICIAL_COLOBOT_BUILD "Official build (changes crash screen text)" OFF)
|
||||
|
||||
# Portable build - load all data from current directory
|
||||
# Hardcode relative paths instead of absolute paths
|
||||
option(USE_RELATIVE_PATHS "Generate relative paths from absolute paths" OFF)
|
||||
|
||||
# Portable build - load all data from the base directory
|
||||
option(PORTABLE "Portable build" OFF)
|
||||
|
||||
# Portable saves - suitable for e.g. putting the whole game on external storage and moving your saves with it
|
||||
|
@ -391,12 +394,12 @@ endif()
|
|||
|
||||
# Installation paths defined before compiling sources
|
||||
if(PORTABLE OR (PLATFORM_WINDOWS AND MXE))
|
||||
# We need to use STRING because PATH doesn't accept relative paths
|
||||
set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory")
|
||||
set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory")
|
||||
set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory")
|
||||
set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory")
|
||||
set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory")
|
||||
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
|
||||
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
|
||||
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory")
|
||||
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory")
|
||||
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory")
|
||||
set(USE_RELATIVE_PATHS ON)
|
||||
elseif(PLATFORM_WINDOWS)
|
||||
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
|
||||
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
|
||||
|
@ -417,6 +420,18 @@ else()
|
|||
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/share/doc/colobot CACHE PATH "Colobot documentation directory")
|
||||
endif()
|
||||
|
||||
# Generate relative paths from absolute paths
|
||||
if(USE_RELATIVE_PATHS)
|
||||
message(STATUS "Generating relative paths")
|
||||
file(RELATIVE_PATH COLOBOT_DATA_DIR ${COLOBOT_INSTALL_BIN_DIR} ${COLOBOT_INSTALL_DATA_DIR})
|
||||
file(RELATIVE_PATH COLOBOT_I18N_DIR ${COLOBOT_INSTALL_BIN_DIR} ${COLOBOT_INSTALL_I18N_DIR})
|
||||
|
||||
add_definitions(-DUSE_RELATIVE_PATHS)
|
||||
else()
|
||||
set(COLOBOT_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR})
|
||||
set(COLOBOT_I18N_DIR ${COLOBOT_INSTALL_I18N_DIR})
|
||||
endif()
|
||||
|
||||
# Subdirectory with sources
|
||||
add_subdirectory(src)
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ pipeline {
|
|||
dir('build/windows') {
|
||||
sh '''
|
||||
# FIXME: without -lsetupapi linking sdl2 fails
|
||||
rm -rf *
|
||||
/opt/mxe/usr/bin/i686-w64-mingw32.static-cmake \
|
||||
-DCMAKE_CXX_STANDARD_LIBRARIES="-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 -lsetupapi" \
|
||||
-DCMAKE_INSTALL_PREFIX=/install \
|
||||
|
@ -53,6 +54,7 @@ pipeline {
|
|||
sh 'mkdir -p build/linux'
|
||||
dir('build/linux') {
|
||||
sh '''
|
||||
rm -rf *
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=/install -DCMAKE_SKIP_INSTALL_RPATH=ON \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DDEV_BUILD=1 -DPORTABLE=1 -DTOOLS=1 -DTESTS=1 -DDESKTOP=1 ../..
|
||||
|
|
|
@ -65,6 +65,8 @@ elseif(PLATFORM_WINDOWS)
|
|||
find_library(TIFF_LIBRARY NAMES tiff.lib)
|
||||
find_library(LZMA_LIBRARY NAMES lzma.lib)
|
||||
find_library(FREETYPE_LIBRARY NAMES freetype.lib)
|
||||
find_library(ICONV_LIBRARY NAMES libiconv.lib)
|
||||
find_library(CHARSET_LIBRARY NAMES libcharset.lib)
|
||||
set(MSVC_LIBS
|
||||
${LIBINTL_LIBRARY}
|
||||
${OPENAL_MSVC_LIBS}
|
||||
|
@ -73,6 +75,8 @@ elseif(PLATFORM_WINDOWS)
|
|||
${BZ2_LIBRARY}
|
||||
${LZMA_LIBRARY}
|
||||
${FREETYPE_LIBRARY}
|
||||
${ICONV_LIBRARY}
|
||||
${CHARSET_LIBRARY}
|
||||
winmm.lib
|
||||
dxguid.lib
|
||||
imm32.lib
|
||||
|
@ -81,6 +85,7 @@ elseif(PLATFORM_WINDOWS)
|
|||
version.lib
|
||||
wsock32.lib
|
||||
ws2_32.lib
|
||||
setupapi.lib
|
||||
)
|
||||
else(${MSVC_STATIC})
|
||||
set(MSVC_LIBS ${LIBINTL_LIBRARY})
|
||||
|
|
|
@ -220,6 +220,30 @@ CSoundInterface* CApplication::GetSound()
|
|||
return m_sound.get();
|
||||
}
|
||||
|
||||
void CApplication::LoadEnvironmentVariables()
|
||||
{
|
||||
auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR");
|
||||
if (!dataDir.empty())
|
||||
{
|
||||
m_pathManager->SetDataPath(dataDir);
|
||||
GetLogger()->Info("Using data dir (based on environment variable): '%s'\n", dataDir.c_str());
|
||||
}
|
||||
|
||||
auto langDir = m_systemUtils->GetEnvVar("COLOBOT_LANG_DIR");
|
||||
if (!langDir.empty())
|
||||
{
|
||||
m_pathManager->SetLangPath(langDir);
|
||||
GetLogger()->Info("Using lang dir (based on environment variable): '%s'\n", langDir.c_str());
|
||||
}
|
||||
|
||||
auto saveDir = m_systemUtils->GetEnvVar("COLOBOT_SAVE_DIR");
|
||||
if (!saveDir.empty())
|
||||
{
|
||||
m_pathManager->SetSavePath(saveDir);
|
||||
GetLogger()->Info("Using save dir (based on environment variable): '%s'\n", saveDir.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
||||
{
|
||||
enum OptionType
|
||||
|
@ -286,15 +310,18 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
|||
GetLogger()->Message("\n");
|
||||
GetLogger()->Message("%s\n", COLOBOT_FULLNAME);
|
||||
GetLogger()->Message("\n");
|
||||
GetLogger()->Message("List of available options:\n");
|
||||
GetLogger()->Message("List of available options and environment variables:\n");
|
||||
GetLogger()->Message(" -help this help\n");
|
||||
GetLogger()->Message(" -debug modes enable debug modes (more info printed in logs; see code for reference of modes)\n");
|
||||
GetLogger()->Message(" -runscene sceneNNN run given scene on start\n");
|
||||
GetLogger()->Message(" -scenetest win every mission right after it's loaded\n");
|
||||
GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n");
|
||||
GetLogger()->Message(" -langdir path set custom language directory path\n");
|
||||
GetLogger()->Message(" environment variable: COLOBOT_LANG_DIR\n");
|
||||
GetLogger()->Message(" -datadir path set custom data directory path\n");
|
||||
GetLogger()->Message(" environment variable: COLOBOT_DATA_DIR\n");
|
||||
GetLogger()->Message(" -savedir path set custom save directory path (must be writable)\n");
|
||||
GetLogger()->Message(" environment variable: COLOBOT_SAVE_DIR\n");
|
||||
GetLogger()->Message(" -mod path load datadir mod from given path\n");
|
||||
GetLogger()->Message(" -resolution WxH set resolution\n");
|
||||
GetLogger()->Message(" -headless headless mode - disables graphics, sound and user interaction\n");
|
||||
|
|
|
@ -164,7 +164,9 @@ public:
|
|||
CSoundInterface* GetSound();
|
||||
|
||||
public:
|
||||
//! Parses commandline arguments
|
||||
//! Loads some data from environment variables
|
||||
void LoadEnvironmentVariables();
|
||||
//! Parses commandline arguments (they take priority)
|
||||
ParseArgsStatus ParseArguments(int argc, char *argv[]);
|
||||
//! Initializes the application
|
||||
bool Create();
|
||||
|
|
|
@ -172,6 +172,8 @@ int main(int argc, char *argv[])
|
|||
int code = 0;
|
||||
CApplication app(systemUtils.get()); // single instance of the application
|
||||
|
||||
app.LoadEnvironmentVariables();
|
||||
|
||||
ParseArgsStatus status = app.ParseArguments(argc, argv);
|
||||
if (status == PARSE_ARGS_FAIL)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ CPathManager::CPathManager(CSystemUtils* systemUtils)
|
|||
: m_dataPath(systemUtils->GetDataPath())
|
||||
, m_langPath(systemUtils->GetLangPath())
|
||||
, m_savePath(systemUtils->GetSaveDir())
|
||||
, m_modAutoloadDir{ m_dataPath + "/mods", m_savePath + "/mods" }
|
||||
, m_modAutoloadDir{}
|
||||
, m_mods{}
|
||||
{
|
||||
}
|
||||
|
@ -130,6 +130,10 @@ void CPathManager::InitPaths()
|
|||
{
|
||||
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
|
||||
GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
|
||||
|
||||
m_modAutoloadDir.push_back(m_dataPath + "/mods");
|
||||
m_modAutoloadDir.push_back(m_savePath + "/mods");
|
||||
|
||||
if (!m_modAutoloadDir.empty())
|
||||
{
|
||||
GetLogger()->Info("Mod autoload dirs:\n");
|
||||
|
|
|
@ -18,5 +18,5 @@
|
|||
|
||||
#cmakedefine PORTABLE_SAVES @PORTABLE_SAVES@
|
||||
|
||||
#define COLOBOT_DEFAULT_DATADIR "@COLOBOT_INSTALL_DATA_DIR@"
|
||||
#define COLOBOT_I18N_DIR "@COLOBOT_INSTALL_I18N_DIR@"
|
||||
#define COLOBOT_DEFAULT_DATADIR "@COLOBOT_DATA_DIR@"
|
||||
#define COLOBOT_I18N_DIR "@COLOBOT_I18N_DIR@"
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
std::unique_ptr<CSystemUtils> CSystemUtils::Create()
|
||||
{
|
||||
|
@ -176,17 +177,41 @@ float CSystemUtils::TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *afte
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string CSystemUtils::GetBasePath()
|
||||
{
|
||||
if (m_basePath.empty())
|
||||
{
|
||||
auto* path = SDL_GetBasePath();
|
||||
m_basePath = path;
|
||||
SDL_free(path);
|
||||
}
|
||||
return m_basePath;
|
||||
}
|
||||
|
||||
std::string CSystemUtils::GetDataPath()
|
||||
{
|
||||
#ifdef USE_RELATIVE_PATHS
|
||||
return GetBasePath() + COLOBOT_DEFAULT_DATADIR;
|
||||
#else
|
||||
return COLOBOT_DEFAULT_DATADIR;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string CSystemUtils::GetLangPath()
|
||||
{
|
||||
#ifdef USE_RELATIVE_PATHS
|
||||
return GetBasePath() + COLOBOT_I18N_DIR;
|
||||
#else
|
||||
return COLOBOT_I18N_DIR;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string CSystemUtils::GetSaveDir()
|
||||
{
|
||||
return "./saves";
|
||||
return GetBasePath() + "saves";
|
||||
}
|
||||
|
||||
std::string CSystemUtils::GetEnvVar(const std::string& name)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -127,6 +127,9 @@ public:
|
|||
/** The difference is \a after - \a before. */
|
||||
virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) = 0;
|
||||
|
||||
//! Returns the path where the executable binary is located (ends with the path separator)
|
||||
virtual std::string GetBasePath();
|
||||
|
||||
//! Returns the data path (containing textures, levels, helpfiles, etc)
|
||||
virtual std::string GetDataPath();
|
||||
|
||||
|
@ -136,9 +139,13 @@ public:
|
|||
//! Returns the save dir location
|
||||
virtual std::string GetSaveDir();
|
||||
|
||||
//! Returns the environment variable with the given name or an empty string if it does not exist
|
||||
virtual std::string GetEnvVar(const std::string &name);
|
||||
|
||||
//! Sleep for given amount of microseconds
|
||||
virtual void Usleep(int usecs) = 0;
|
||||
|
||||
private:
|
||||
std::string m_basePath;
|
||||
std::vector<std::unique_ptr<SystemTimeStamp>> m_timeStamps;
|
||||
};
|
||||
|
|
|
@ -102,23 +102,23 @@ std::string CSystemUtilsLinux::GetSaveDir()
|
|||
std::string savegameDir;
|
||||
|
||||
// Determine savegame dir according to XDG Base Directory Specification
|
||||
char *envXDG_DATA_HOME = getenv("XDG_DATA_HOME");
|
||||
if (envXDG_DATA_HOME == nullptr)
|
||||
auto envXDG_DATA_HOME = GetEnvVar("XDG_DATA_HOME");
|
||||
if (envXDG_DATA_HOME.empty())
|
||||
{
|
||||
char *envHOME = getenv("HOME");
|
||||
if (envHOME == nullptr)
|
||||
auto envHOME = GetEnvVar("HOME");
|
||||
if (envHOME.empty())
|
||||
{
|
||||
GetLogger()->Warn("Unable to find directory for saves - using current directory");
|
||||
savegameDir = "./saves";
|
||||
GetLogger()->Warn("Unable to find directory for saves - using default directory");
|
||||
savegameDir = CSystemUtils::GetSaveDir();
|
||||
}
|
||||
else
|
||||
{
|
||||
savegameDir = std::string(envHOME) + "/.local/share/colobot";
|
||||
savegameDir = envHOME + "/.local/share/colobot";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
savegameDir = std::string(envXDG_DATA_HOME) + "/colobot";
|
||||
savegameDir = envXDG_DATA_HOME + "/colobot";
|
||||
}
|
||||
GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str());
|
||||
|
||||
|
@ -126,6 +126,17 @@ std::string CSystemUtilsLinux::GetSaveDir()
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string CSystemUtilsLinux::GetEnvVar(const std::string& name)
|
||||
{
|
||||
char* envVar = getenv(name.c_str());
|
||||
if (envVar != nullptr)
|
||||
{
|
||||
GetLogger()->Trace("Detected environment variable %s = %s\n", name.c_str(), envVar);
|
||||
return std::string(envVar);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CSystemUtilsLinux::Usleep(int usec)
|
||||
{
|
||||
usleep(usec);
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
std::string GetSaveDir() override;
|
||||
|
||||
std::string GetEnvVar(const std::string& name) override;
|
||||
|
||||
void Usleep(int usec) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -113,6 +113,12 @@ std::string CSystemUtilsMacOSX::GetSaveDir()
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string CSystemUtilsMacOSX::GetEnvVar(const std::string& str)
|
||||
{
|
||||
// TODO: I have no Mac
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void CSystemUtilsMacOSX::Usleep(int usec)
|
||||
{
|
||||
usleep(usec);
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
std::string GetLangPath() override;
|
||||
std::string GetSaveDir() override;
|
||||
|
||||
std::string GetEnvVar(const std::string& name) override;
|
||||
|
||||
void Usleep(int usec) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -115,15 +115,15 @@ std::string CSystemUtilsWindows::GetSaveDir()
|
|||
#else
|
||||
std::string savegameDir;
|
||||
|
||||
wchar_t* envUSERPROFILE = _wgetenv(L"USERPROFILE");
|
||||
if (envUSERPROFILE == nullptr)
|
||||
auto envUSERPROFILE = GetEnvVar("USERPROFILE");
|
||||
if (envUSERPROFILE.empty())
|
||||
{
|
||||
GetLogger()->Warn("Unable to find directory for saves - using current directory");
|
||||
savegameDir = "./saves";
|
||||
GetLogger()->Warn("Unable to find directory for saves - using default directory");
|
||||
savegameDir = CSystemUtils::GetSaveDir();
|
||||
}
|
||||
else
|
||||
{
|
||||
savegameDir = UTF8_Encode(std::wstring(envUSERPROFILE)) + "\\colobot";
|
||||
savegameDir = envUSERPROFILE + "\\colobot";
|
||||
}
|
||||
GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str());
|
||||
|
||||
|
@ -131,6 +131,22 @@ std::string CSystemUtilsWindows::GetSaveDir()
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string CSystemUtilsWindows::GetEnvVar(const std::string& name)
|
||||
{
|
||||
std::wstring wname(name.begin(), name.end());
|
||||
wchar_t* envVar = _wgetenv(wname.c_str());
|
||||
if (envVar == nullptr)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string var = UTF8_Encode(std::wstring(envVar));
|
||||
GetLogger()->Trace("Detected environment variable %s = %s\n", name.c_str(), var.c_str());
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
void CSystemUtilsWindows::Usleep(int usec)
|
||||
{
|
||||
LARGE_INTEGER ft;
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
|
||||
std::string GetSaveDir() override;
|
||||
|
||||
std::string GetEnvVar(const std::string& name) override;
|
||||
|
||||
void Usleep(int usec) override;
|
||||
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue