Стандартные пути

This commit is contained in:
Andrei Astafev 2019-11-25 15:08:34 +03:00
parent daab07fa6a
commit d6c1e42a26
9 changed files with 126 additions and 468 deletions

View File

@ -33,8 +33,6 @@ target_include_directories(${current_target} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIR
target_compile_options(${current_target} PUBLIC "${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") target_compile_options(${current_target} PUBLIC "${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
target_link_libraries(${current_target} myx-filesystem) target_link_libraries(${current_target} myx-filesystem)
target_link_libraries(${current_target} whereamipp)
target_link_libraries(${current_target} whereami)
target_link_libraries(${current_target} Qt5::Core) target_link_libraries(${current_target} Qt5::Core)
# Имя выходного файла для цели # Имя выходного файла для цели

View File

@ -1,5 +1,9 @@
#include <myx/base/config.hpp>
#include <myx/filesystem/paths.hpp> #include <myx/filesystem/paths.hpp>
#include <QCoreApplication>
namespace MF = myx::filesystem; namespace MF = myx::filesystem;
@ -7,6 +11,7 @@ int main( int argc, char** argv )
{ {
(void)argc; (void)argc;
(void)argv; (void)argv;
QCoreApplication::setApplicationName( PROJECT_NAME );
MF::Paths paths; MF::Paths paths;
paths.updatePaths(); paths.updatePaths();

View File

@ -3,14 +3,14 @@ set(current_target filesystem)
# Список файлов исходных текстов # Список файлов исходных текстов
set(current_target_sources set(current_target_sources
${CMAKE_CURRENT_SOURCE_DIR}/current_executable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp ${CMAKE_CURRENT_SOURCE_DIR}/paths.cpp
${CMAKE_CURRENT_SOURCE_DIR}/whereami.cpp
) )
# Список заголовочных файлов (используется для установки) # Список заголовочных файлов (используется для установки)
set(current_target_headers set(current_target_headers
${CMAKE_CURRENT_SOURCE_DIR}/current_executable.hpp
${CMAKE_CURRENT_SOURCE_DIR}/paths.hpp ${CMAKE_CURRENT_SOURCE_DIR}/paths.hpp
${CMAKE_CURRENT_SOURCE_DIR}/whereami.hpp
) )
add_common_library(TARGET ${current_target} add_common_library(TARGET ${current_target}

View File

@ -0,0 +1,43 @@
#include "current_executable.hpp"
#include <myx/base/config.hpp>
#include <paths.h>
#include <QString>
#include <QCoreApplication>
namespace myx {
namespace filesystem {
CurrentExecutable::CurrentExecutable() :
m_procFilePath( "/proc/self/exe" )
{
auto canonicalFilePath = m_procFilePath.canonicalFilePath();
auto canonicalPath = m_procFilePath.canonicalPath();
m_fileName = canonicalFilePath.remove( canonicalPath ).remove( '/' );
m_canonicalFilePath = canonicalFilePath;
m_canonicalPath = canonicalPath;
}
QFileInfo CurrentExecutable::canonicalFilePath() const
{
return( m_canonicalFilePath );
}
QDir CurrentExecutable::canonicalPath() const
{
return( m_canonicalPath );
}
QString CurrentExecutable::fileName() const
{
return( m_fileName );
}
} // namespace filesystem
} // namespace myx

View File

@ -0,0 +1,30 @@
#ifndef MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_
#define MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_
#include <QString>
#include <QDir>
#include <QFileInfo>
namespace myx {
namespace filesystem {
class CurrentExecutable
{
QFileInfo m_procFilePath;
QFileInfo m_canonicalFilePath;
QDir m_canonicalPath;
QString m_fileName;
public:
CurrentExecutable();
QFileInfo canonicalFilePath() const;
QDir canonicalPath() const;
QString fileName() const;
};
} // namespace filesystem
} // namespace myx
#endif // MYX_FILESYSTEM_CURRENT_EXECUTABLE_HPP_

View File

@ -1,7 +1,7 @@
#include "paths.hpp" #include "paths.hpp"
#include <myx/base/config.hpp> #include <myx/base/config.hpp>
#include <myx/filesystem/whereami.hpp> #include <myx/filesystem/current_executable.hpp>
#include <paths.h> #include <paths.h>
#include <QString> #include <QString>
@ -13,13 +13,7 @@ namespace filesystem {
QString Paths::executableFileName() const QString Paths::executableFileName() const
{ {
return( m_executableFileName ); return( m_currentExecutable.fileName() );
}
void Paths::setExecutableFileName( const QString& executableFileName )
{
m_executableFileName = executableFileName;
} }
@ -37,13 +31,7 @@ void Paths::setConfigFileName( const QString& configFileName )
QFileInfo Paths::executableFilePath() const QFileInfo Paths::executableFilePath() const
{ {
return( m_executableFilePath ); return( m_currentExecutable.canonicalFilePath() );
}
void Paths::setExecutableFilePath( const QFileInfo& executableFilePath )
{
m_executableFilePath = executableFilePath;
} }
@ -59,20 +47,36 @@ void Paths::setConfigFilePath( const QFileInfo& configFilePath )
} }
Paths::Paths() QDir Paths::logDirectory() const
{
return( m_logDirectory );
}
void Paths::setLogDirectory( const QString& logDirectory )
{
m_logDirectory = logDirectory;
}
Paths::Paths( const QString& configFileExtension ) :
m_configFileExtension( configFileExtension )
{ {
m_prefixDirectory = "/opt/" + QCoreApplication::organizationName().toLower() + m_prefixDirectory = "/opt/" + QCoreApplication::organizationName().toLower() +
"/" + QCoreApplication::applicationName().toLower(); "/" + QCoreApplication::applicationName().toLower();
m_binaryDirectory = m_prefixDirectory.absolutePath() + "/bin"; auto pd = m_prefixDirectory.absolutePath();
m_configDirectory = m_prefixDirectory.absolutePath() + "/etc"; m_binaryDirectory = pd + "/bin";
m_cacheDirectory = m_prefixDirectory.absolutePath() + "/var"; m_configDirectory = pd + "/etc";
m_cacheDirectory = pd + "/var";
m_logDirectory = pd + "/var/log";
m_tempDirectory = QString::fromLocal8Bit( qgetenv( qPrintable( "TMPDIR" ) ) ); m_tempDirectory = QString::fromLocal8Bit( qgetenv( qPrintable( "TMPDIR" ) ) );
m_dataDirectory = m_prefixDirectory.absolutePath() + "/share"; m_dataDirectory = pd + "/share";
m_homeDirectory = QString::fromLocal8Bit( qgetenv( qPrintable( "HOME" ) ) ); m_homeDirectory = QString::fromLocal8Bit( qgetenv( qPrintable( "HOME" ) ) );
m_executableFileName = QCoreApplication::applicationName().toLower(); m_configFileName = QCoreApplication::applicationName().toLower() +
m_configFileName = m_executableFileName + ".conf"; "." + m_configFileExtension;
m_executableFilePath = m_binaryDirectory.absolutePath() + "/" + m_executableFileName; m_configFilePath = m_binaryDirectory.absolutePath() +
m_configFilePath = m_binaryDirectory.absolutePath() + "/" + m_configFileName; "/" + m_configFileName;
if ( m_tempDirectory.absolutePath().isEmpty() || ( m_tempDirectory.path() == "." ) ) if ( m_tempDirectory.absolutePath().isEmpty() || ( m_tempDirectory.path() == "." ) )
@ -156,20 +160,18 @@ void Paths::setDataDirectory( const QString& dataDirectory )
bool Paths::updatePaths() bool Paths::updatePaths()
{ {
whereami::whereami_path_t executablePath = whereami::getExecutablePath(); m_binaryDirectory = m_currentExecutable.canonicalPath();
m_executableFileName = QString::fromStdString( executablePath.basename() );
m_binaryDirectory = QString::fromStdString( executablePath.dirname() );
m_executableFilePath = QFile( m_binaryDirectory.absolutePath() + "/" + m_executableFileName );
if ( m_binaryDirectory.absolutePath().endsWith( "/bin" ) ) if ( m_binaryDirectory.absolutePath().endsWith( "/bin" ) )
{ {
m_prefixDirectory = m_binaryDirectory.absolutePath().remove( QRegExp( "/bin$" ) ); m_prefixDirectory = m_binaryDirectory.absolutePath().remove( QRegExp( "/bin$" ) );
m_configDirectory = m_prefixDirectory.absolutePath() + "/etc"; m_configDirectory = m_prefixDirectory.absolutePath() + "/etc";
m_cacheDirectory = m_prefixDirectory.absolutePath() + "/var"; m_cacheDirectory = m_prefixDirectory.absolutePath() + "/var";
m_logDirectory = m_prefixDirectory.absolutePath() + "/var/log";
m_dataDirectory = m_prefixDirectory.absolutePath() + "/share"; m_dataDirectory = m_prefixDirectory.absolutePath() + "/share";
m_configFilePath = QFile( m_configDirectory.absolutePath() + "/" + m_configFilePath = QFile( m_configDirectory.absolutePath() +
QCoreApplication::applicationName() + ".conf" ); "/" + QCoreApplication::applicationName() +
"." + m_configFileExtension );
} }
if ( m_prefixDirectory.absolutePath().startsWith( "/opt" ) || if ( m_prefixDirectory.absolutePath().startsWith( "/opt" ) ||
@ -201,6 +203,7 @@ bool Paths::updatePaths()
m_cacheDirectory = cacheDirectory + "/" + m_cacheDirectory = cacheDirectory + "/" +
QCoreApplication::organizationName().toLower() + "/" + QCoreApplication::organizationName().toLower() + "/" +
QCoreApplication::applicationName().toLower(); QCoreApplication::applicationName().toLower();
m_logDirectory = m_cacheDirectory.absolutePath() + "/log";
} }
return( true ); return( true );
@ -214,6 +217,7 @@ bool Paths::makeDefaultDirectories()
if ( !m_dataDirectory.mkpath( m_dataDirectory.absolutePath() ) ) { status = false; } if ( !m_dataDirectory.mkpath( m_dataDirectory.absolutePath() ) ) { status = false; }
if ( !m_configDirectory.mkpath( m_configDirectory.absolutePath() ) ) { status = false; } if ( !m_configDirectory.mkpath( m_configDirectory.absolutePath() ) ) { status = false; }
if ( !m_cacheDirectory.mkpath( m_cacheDirectory.absolutePath() ) ) { status = false; } if ( !m_cacheDirectory.mkpath( m_cacheDirectory.absolutePath() ) ) { status = false; }
if ( !m_logDirectory.mkpath( m_logDirectory.absolutePath() ) ) { status = false; }
return( status ); return( status );
} }

View File

@ -1,6 +1,8 @@
#ifndef MYX_FILESYSTEM_PATHS_HPP_ #ifndef MYX_FILESYSTEM_PATHS_HPP_
#define MYX_FILESYSTEM_PATHS_HPP_ #define MYX_FILESYSTEM_PATHS_HPP_
#include <myx/filesystem/current_executable.hpp>
#include <QString> #include <QString>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@ -17,14 +19,16 @@ class Paths
QDir m_cacheDirectory; QDir m_cacheDirectory;
QDir m_tempDirectory; QDir m_tempDirectory;
QDir m_dataDirectory; QDir m_dataDirectory;
QDir m_logDirectory;
QDir m_homeDirectory; QDir m_homeDirectory;
QString m_executableFileName; QString m_configFileExtension;
QString m_configFileName; QString m_configFileName;
QFileInfo m_executableFilePath;
QFileInfo m_configFilePath; QFileInfo m_configFilePath;
CurrentExecutable m_currentExecutable;
public: public:
Paths(); Paths( const QString& configFileExtension = "conf" );
QDir prefixDirectory() const; QDir prefixDirectory() const;
void setPrefixDirectory( const QString& prefixDirectory ); void setPrefixDirectory( const QString& prefixDirectory );
QDir binaryDirectory() const; QDir binaryDirectory() const;
@ -37,12 +41,12 @@ public:
void setTempDirectory( const QString& tempDirectory ); void setTempDirectory( const QString& tempDirectory );
QDir dataDirectory() const; QDir dataDirectory() const;
void setDataDirectory( const QString& dataDirectory ); void setDataDirectory( const QString& dataDirectory );
QDir logDirectory() const;
void setLogDirectory( const QString& logDirectory );
QString executableFileName() const; QString executableFileName() const;
void setExecutableFileName( const QString& executableFileName );
QString configFileName() const; QString configFileName() const;
void setConfigFileName( const QString& configFileName ); void setConfigFileName( const QString& configFileName );
QFileInfo executableFilePath() const; QFileInfo executableFilePath() const;
void setExecutableFilePath( const QFileInfo& executableFilePath );
QFileInfo configFilePath() const; QFileInfo configFilePath() const;
void setConfigFilePath( const QFileInfo& configFilePath ); void setConfigFilePath( const QFileInfo& configFilePath );

View File

@ -1,305 +0,0 @@
#include <myx/filesystem/whereami.hpp>
namespace whereami {
namespace {
#ifdef __cplusplus
extern "C" {
#endif
#include <cstdlib>
#ifndef WAI_NOINLINE
#if defined( _MSC_VER )
#define WAI_NOINLINE __declspec( noinline )
#elif defined( __GNUC__ )
#define WAI_NOINLINE __attribute__( ( noinline ) )
#else
#error unsupported compiler
#endif
#endif
#if defined( _MSC_VER )
#define WAI_RETURN_ADDRESS() _ReturnAddress()
#elif defined( __GNUC__ )
#define WAI_RETURN_ADDRESS() __builtin_extract_return_addr( __builtin_return_address( 0 ) )
#else
#error unsupported compiler
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( __linux__ )
#include <linux/limits.h>
#else
#include <limits.h>
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#if !defined( WAI_PROC_SELF_EXE )
#define WAI_PROC_SELF_EXE "/proc/self/exe"
#endif
int getExecutablePath( char* out, int capacity, int* dirname_length )
{
char buffer[PATH_MAX];
char* resolved = nullptr;
int length = -1;
for (;; )
{
resolved = realpath( WAI_PROC_SELF_EXE, buffer );
if ( !resolved )
{
break;
}
length = static_cast< int >( strlen( resolved ) );
if ( length <= capacity )
{
memcpy( out, resolved, static_cast< size_t >( length ) );
if ( dirname_length )
{
for ( int i = length - 1; i >= 0; --i )
{
if ( out[i] == '/' )
{
*dirname_length = i;
break;
}
}
}
}
break;
}
return( length );
} // getExecutablePath
#if !defined( WAI_PROC_SELF_MAPS_RETRY )
#define WAI_PROC_SELF_MAPS_RETRY 5
#endif
#if !defined( WAI_PROC_SELF_MAPS )
#if defined( __sun )
#define WAI_PROC_SELF_MAPS "/proc/self/map"
#else
#define WAI_PROC_SELF_MAPS "/proc/self/maps"
#endif
#endif
#if defined( __ANDROID__ ) || defined( ANDROID )
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
WAI_NOINLINE
int getModulePath( char* out, int capacity, int* dirname_length )
{
int length = -1;
FILE* maps = nullptr;
for ( int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r )
{
maps = fopen( WAI_PROC_SELF_MAPS, "r" );
if ( !maps )
{
break;
}
for (;; )
{
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
uint64_t low, high;
char perms[5];
uint64_t offset;
uint32_t major, minor;
char path[PATH_MAX];
uint32_t inode;
if ( !fgets( buffer, sizeof( buffer ), maps ) )
{
break;
}
if ( sscanf( buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path ) == 8 )
{
uint64_t addr = reinterpret_cast< uintptr_t >( WAI_RETURN_ADDRESS() );
if ( ( low <= addr ) && ( addr <= high ) )
{
char* resolved = nullptr;
resolved = realpath( path, buffer );
if ( resolved == nullptr )
{
break;
}
length = static_cast< int >( strlen( resolved ) );
if ( length <= capacity )
{
memcpy( out, resolved, static_cast< size_t >( length ) );
if ( dirname_length )
{
for ( int i = length - 1; i >= 0; --i )
{
if ( out[i] == '/' )
{
*dirname_length = i;
break;
}
}
}
}
break;
}
}
}
fclose( maps );
maps = nullptr;
if ( length != -1 )
{
break;
}
}
if ( maps != nullptr )
{
fclose( maps );
}
return( length );
} // getModulePath
#ifdef __cplusplus
} // namespace
#endif
} // namespace
whereami_string_t whereami_path_t::dirname() const
{
return( m_path.substr( 0, static_cast< size_t >( m_dirnameLength ) ) );
}
whereami_string_t whereami_path_t::basename() const
{
return( m_path.substr( static_cast< size_t >( m_dirnameLength + 1 ) ) );
}
#if defined( WHEREAMI_CXX11 )
whereami_path_t::operator whereami_string_t() &&
{
return( std::move( m_path ) );
}
whereami_path_t::operator whereami_string_t() const &
{
return( m_path );
}
#else
whereami_path_t::operator const whereami_string_t&() const
{
return( m_path );
}
#endif // if defined( WHEREAMI_CXX11 )
#if defined( WHEREAMI_CXX11 )
whereami_path_t::whereami_path_t( whereami_string_t&& path, int dirname_length ) noexcept :
m_path ( std::move( path ) ),
m_dirnameLength( dirname_length )
{
}
#else
whereami_path_t::whereami_path_t( whereami_string_t& path, int dirname_length ) :
m_path ( path ),
m_dirnameLength( dirname_length )
{
}
#endif
#if !defined( WHEREAMI_DISABLE_OSTREAM )
std::ostream& operator<<( std::ostream& os, const whereami_path_t& path )
{
return( os << path.m_path );
}
#endif
whereami_path_t getExecutablePath()
{
whereami_string_t path;
int dirname_length = -1;
int length = getExecutablePath( nullptr, 0, nullptr );
if ( length != -1 )
{
path.resize( static_cast< size_t >( length ) );
getExecutablePath( &path[0], length, &dirname_length );
}
#if defined( WHEREAMI_CXX11 )
return( whereami_path_t( std::move( path ), dirname_length ) );
#else
return( whereami_path_t( path, dirname_length ) );
#endif
}
whereami_path_t getModulePath()
{
whereami_string_t path;
int dirname_length = -1;
int length = getModulePath( nullptr, 0, nullptr );
if ( length != -1 )
{
path.resize( static_cast< size_t >( length ) );
getModulePath( &path[0], length, &dirname_length );
}
#if defined( WHEREAMI_CXX11 )
return( whereami_path_t( std::move( path ), dirname_length ) );
#else
return( whereami_path_t( path, dirname_length ) );
#endif
}
} // namespace whereami

View File

@ -1,121 +0,0 @@
#ifndef WHEREAMIPP_HPP_
#define WHEREAMIPP_HPP_
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns the path to the current executable.
*
* Usage:
* - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to
* retrieve the length of the path
* - allocate the destination buffer with `path = (char*)malloc(length + 1);`
* - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the
* path
* - add a terminal NUL character with `path[length] = '\0';`
*
* @param out destination buffer, optional
* @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part
* of the path.
*
* @return the length of the executable path on success (without a terminal NUL
* character), otherwise `-1`
*/
int getExecutablePath( char* out, int capacity, int* dirname_length );
/**
* Returns the path to the current module.
*
* Usage:
* - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve
* the length of the path
* - allocate the destination buffer with `path = (char*)malloc(length + 1);`
* - call `wai_getModulePath(path, length, NULL)` again to retrieve the path
* - add a terminal NUL character with `path[length] = '\0';`
*
* @param out destination buffer, optional
* @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part
* of the path.
*
* @return the length of the module path on success (without a terminal NUL
* character), otherwise `-1`
*/
int getModulePath( char* out, int capacity, int* dirname_length );
#ifdef __cplusplus
}
#endif
#if !defined( WHEREAMI_STRING_T )
#include <string>
typedef std::string whereami_string_t;
#else
typedef WHEREAMI_STRING_T whereami_string_t;
#endif
#if !defined( WHEREAMI_DISABLE_OSTREAM )
#include <ostream>
#endif
#if ( defined ( __cplusplus ) && ( __cplusplus > 199711L ) ) || ( defined( _MSC_FULL_VER ) && ( _MSC_FULL_VER >= 150020706 ) )
#define WHEREAMI_CXX11
#endif
#if defined( __GNUC__ )
#if ( ( __GNUC__ * 100 + __GNUC_MINOR__ ) < 408 )
#undef WHEREAMI_CXX11
#endif
#endif
namespace whereami {
class whereami_path_t
{
public:
#if defined( WHEREAMI_CXX11 )
operator whereami_string_t() &&;
operator whereami_string_t() const &;
#else
operator const whereami_string_t&() const;
#endif
whereami_string_t dirname() const;
whereami_string_t basename() const;
private:
whereami_path_t();
#if defined( WHEREAMI_CXX11 )
whereami_path_t( whereami_string_t&& path, int dirname_length ) noexcept;
#else
whereami_path_t( whereami_string_t& m_path, int m_dirnameLength );
#endif
friend whereami_path_t getExecutablePath();
friend whereami_path_t getModulePath();
#if !defined( WHEREAMI_DISABLE_OSTREAM )
friend std::ostream& operator<<( std::ostream& os, const whereami_path_t& m_path );
#endif
whereami_string_t m_path;
int m_dirnameLength;
}; // class whereami_path_t
/**
* Returns the path to the current executable.
*/
whereami_path_t getExecutablePath();
/**
* Returns the path to the current module.
*/
whereami_path_t getModulePath();
} // namespace whereami
#endif // #ifndef WHEREAMIPP_H