Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Fullpath or execution dir on widows/linux/mac[SOLVED]  (Read 27719 times)

0 Members and 1 Guest are viewing this topic.

wmbuRn

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • Email
Fullpath or execution dir on widows/linux/mac[SOLVED]
« on: July 28, 2013, 04:35:44 pm »
I read a tons of post of the same question from google search but it didnt help. Can somebody pooint me to a post i can read to figure this one out.

I know using full path doesnt require and platform specific code. But doing so i have to:
1. Make windows only application by changing [ if (!texture.loadFromFile("c:/somDir/image.png" ))
2. Make linux only applocation by changing  [ if (!texture.loadFromFile("/home/user/programDir/image.png"))
Which is not best soluton since i cant know
1. Where the user will put the program
2. The username from linux user.

Hence, it is better to use execution dir. But how to do it? And how will this line look like  [ if (!texture.loadFromFile("image.png")) also looking for a reliable cross-platform code, or platform specific that can be put into cpp file and thati can compile it with gcc on diferent sistems.

Thank you in advance
wmbuRn
« Last Edit: July 31, 2013, 12:09:27 am by wmbuRn »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11016
    • View Profile
    • development blog
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #1 on: July 28, 2013, 07:11:35 pm »
You should never use absolute path, especially if you want to use the code for multiple OS.
Instead you simply use relative path and relative means that it starts looking in the working directory. If you double click an exe on Windows in the explorer, the working directory will be the directory where the exe is in. But if you'd start the binary from the command line, the working directory is the one you're calling the binary from.

Usually you can just go with a relative path and don't where from where it gets executed (so texture.loadFromFile("image.png") is fine). In some cases however, you might want to force set the working directory from the application itself. This needs some code for each platform, since it's handled differently on each.

The code examples of SFML are all cross-platform. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: Fullpath or execution dir on widows/linux/mac
« Reply #2 on: July 28, 2013, 07:22:22 pm »
As eXpl0it3r said, relative paths are the good way to go.
The only drawback is that sometimes, the executable is launched from another directory via some symlinks/shortcuts and depending on the OS+Link configuration it will or will not be launched as if it were in the original directory.

If you realy want to have the executable path for whatever reason, you can have it with the argv parameter given to your main function, the first string is always (windows/unix) the path of the execultable the user has doubled clicked on/launched from command prompt.


Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #3 on: July 28, 2013, 07:35:40 pm »
On OS X, you can embed your resources into your application. Then use the provided resourcePath() function to get their path as explained in the SFML and Xcode tutorial.

On Linux, or Windows, as said above, you can use paths relative to your application binary. Then get the absolute path of your app (see this stackoverflow question for how-to) and combine them to get a full path to your resources. (You can implement resourcePath() for Linux/Windows like that.)




Alternatively, a few years ago I wrote this helper function. Then you can create an installer / tell your users where to put the data. But that's more useful to save settings or alike.
SFML / OS X developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11016
    • View Profile
    • development blog
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #4 on: July 28, 2013, 10:01:07 pm »
If you realy want to have the executable path for whatever reason, you can have it with the argv parameter given to your main function, the first string is always (windows/unix) the path of the execultable the user has doubled clicked on/launched from command prompt.
Unfortunately this is not a guaranteed way to handle it. It might work in some cases, but there's not guarantee.

I've once written the code piece, which should work on Windows and Linux. For more OS you can look up this Stackoverflow question. Since we were already using Boost Filesystem, I used it to extract the directory path from the executable path.
std::string Client::get_executable_path() {
        char buff[1024];
#if defined( LINUX )
        ssize_t len = ::readlink( "/proc/self/exe", buff, sizeof(buff)-1 );
        if (len != -1) {
                buff[len] = '\0';
                return boost::filesystem::path( buff ).parent_path.string();
        }
    else {
                std::cerr << "Failed to retrieve the executable path." << std::endl;
                return boost::filesystem::current_path().string();
        }
#elif defined( WINDOWS )
        HMODULE module_handle = GetModuleHandle( nullptr );
        GetModuleFileName( module_handle, buff, sizeof(buff) );
        return boost::filesystem::path( buff ).parent_path().string();
#else
        #error "MISSING CODE :-( - See StackOverflow 1023306"
#endif
}

Further more, if you're again using Boost Filesystem you could also use the following code piece to change the working directory:
// Change the working directory to the executable path
if( boost::filesystem::current_path().string() != get_executable_path() )  {
        boost::filesystem::current_path( get_executable_path() );
}
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

wmbuRn

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #5 on: July 29, 2013, 02:07:27 am »
I was using folder "Data/ items here.png" or "Data/Group X/images here.png" which works when program is started via terminal. But i does not works when its started on double click. I only see black screen [even when Data folder is near executable]. I am working on linux. And i only want program to find that "Data" folder which will be near executable, which i cant do.

Quote
For more OS you can look up this Stackoverflow question.
Yup i have bookmarked that awhile ago. So i will implement it with #DEFINE  (WINDOW) etc etc, i have never done that so it will be downhill from now :) Thank for helping guys i will test out code and see if its working :)

wmbuRn

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #6 on: July 30, 2013, 04:09:09 pm »
#ifdef _WIN32
#include <windows.h>

std::string getexepath()
  {
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
  }
#endif

#ifdef __linux
#include <unistd.h>

std::string getexepath()
  {
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
 
#endif
#ifdef __APPLE__
// nothing to do here [yet]
#endif
 

I have not tested this on windows [yet] but on linux i get full path
/home/hidden/Developing/test/bin/Debug/test.out << test.out is the actual file [ the application] and i want to get path /home/hidden/Developing/test/bin/Debug/ [ without test.out ]
so i can use commands like
std::string Path =  getexepath(); // which will hold path without test.out
and latter in code
sf::Image background;
if (!background.loadFromFile(Path + "/Data/background.jpg"))
return -1;
 

So question is: How to modify getexepath() function to return path without its executable?
« Last Edit: July 30, 2013, 04:27:18 pm by wmbuRn »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #7 on: July 30, 2013, 04:26:50 pm »
On unix, you can use stat() like in this SO to test if the path is a directory or a file.

In the latter case, remove every character until the last '/'. That can be done like that:

    std::string::size_type lastSlashPos = mAppDirectory.rfind('/');
    if (lastSlashPos != std::string::npos) {
        mAppDirectory = mAppDirectory.substr(0, lastSlashPos + 1);
    }
SFML / OS X developer

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: Fullpath or execution dir on widows/linux/mac
« Reply #8 on: July 30, 2013, 04:36:52 pm »
Still don't get why you need the whole path to get an image instead of using relative path.

If the problem is because you copy/paste your executable somewhere else, then it's because you just shouldn't do that but use symbolic or physical links instead (IMO)

wmbuRn

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #9 on: July 30, 2013, 04:51:01 pm »
Relative path doesnt work when i start application with double click. i did
sf::Image background;
if (!background.loadFromFile("/Data/background.jpg"))
return -1;
 
Which works when
1. I start application from IDE [ Code::Blocks]
2. When i start compiled program from terminal [ with ./programName

But it doesnt work when i double click on application, i only see black screen.

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: Fullpath or execution dir on widows/linux/mac
« Reply #10 on: July 30, 2013, 04:56:39 pm »
Isn't the first slash wrong ? Generally, it means "root". If the Data folter is next to your executable, so you should have :
background.loadFromFile("Data/background.jpg")

But I don't think it will solve your issue.

When I double click on a program that have the data next to it, I've no problem (linux or windows, whatever).
Just make sure the executable and the Data folder are together.

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #11 on: July 30, 2013, 05:04:41 pm »
Still don't get why you need the whole path to get an image instead of using relative path.

If the problem is because you copy/paste your executable somewhere else, then it's because you just shouldn't do that but use symbolic or physical links instead (IMO)

Unfortunately it doesn't work like that.

Take this simple program:

#include <unistd.h>
#include <iostream>

int main(int, char**) {
    char* pwd = getwd(NULL);
    std::cout << "Working directory: " << pwd;
    free(pwd);
    return 0;
}

 

Compile it with g++ main.cpp -o exe. Here are some outputs depending on the launch command:

~/D/tmp> ./exe
Working directory: /Users/m/Desktop/tmp~
~/D/tmp> cd inner/
~/D/t/inner> ../exe
Working directory: /Users/m/Desktop/tmp/inner~
~/D/t/inner> ln -s ../exe lnexe
~/D/t/inner> ./lnexe
Working directory: /Users/m/Desktop/tmp/inner~
~/D/t/inner> cd ..
~/D/tmp> ./inner/lnexe
Working directory: /Users/m/Desktop/tmp~

As you can see, you need the full path to your exe's directoy to load resources. Using only a relative path will fail in most situations.
SFML / OS X developer

wmbuRn

  • Jr. Member
  • **
  • Posts: 58
    • View Profile
    • Email
Re: Fullpath or execution dir on widows/linux/mac
« Reply #12 on: July 30, 2013, 05:10:13 pm »
Isn't the first slash wrong ? Generally, it means "root". If the Data folter is next to your executable, so you should have :
background.loadFromFile("Data/background.jpg")

I took code from my previous post, forgot to remove "/"
so it is "Data/background.jpg")

Quote
When I double click on a program that have the data next to it, I've no problem (linux or windows, whatever).
Just make sure the executable and the Data folder are together.
I do have problem, Data folder is in the same folder with executable. Here is terminal output dir

/Developing/test/bin/Debug$ dir
Data  test.out
« Last Edit: July 30, 2013, 05:14:21 pm by wmbuRn »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Fullpath or execution dir on widows/linux/mac
« Reply #13 on: July 30, 2013, 05:11:03 pm »
Hiura, but that defeats the whole purpose of relative paths. Isn't there a possibility to keep the working directory unchanged when using symbolic links? On Windows, a link doesn't affect the working directory by default, but you can customize it.

I would simply require the user to invoke the program in the correct directory. Generous people may provide a meaningful error message ;)
« Last Edit: July 30, 2013, 05:14:13 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Lo-X

  • Hero Member
  • *****
  • Posts: 618
    • View Profile
    • My personal website, with CV, portfolio and projects
Re: Fullpath or execution dir on widows/linux/mac
« Reply #14 on: July 30, 2013, 05:17:41 pm »
That's what I say, you shouldn't use it like that but use symbolic links instead if you want to create some kind of "shortcuts" to the program.

If I'm not mistaken, your ln command here should give the absolute path to the executable so when you launch the program though the symbolic link, it launch it from the real directory where the data is.

Well, of course if users start playing and launching the program command line from the other end of the file system, then... it fails. I realize that.
What I'm saying is that a double click on the executable should work, a command line from right directory or a proper link too. So IMO with that your basic-user-proof.

To be computer-guy-proof is another story indeed.

Hiura, but that defeats the whole purpose of relative paths. Isn't there a possibility to keep the working directory unchanged when using symbolic links? On Windows, a link doesn't affect the working directory by default, but you can customize it.

I would simply require the user to invoke the program in the correct directory. Generous people may provide a meaningful error message ;)

I think
ln -s /full/path/to/my/program/exe MyShortcut
works as intended (and as on windows). Can't remember if there's another option somewhere, I'll give it a try as soon as I'm home =)