likle / cwalk

Path library for C/C++. Cross-Platform for Linux, FreeBSD, Windows and MacOS. Supports UNIX and Windows path styles on those platforms.
https://likle.github.io/cwalk/
MIT License
253 stars 40 forks source link

Add function that returns program location #20

Closed ddalcino closed 3 years ago

ddalcino commented 3 years ago

It would be really useful to me (and others, I'm sure) if your project had a function that returns the absolute path to the executable that's calling the function. For example, if you were running a program whose binary exists at /usr/bin/myprog, and arvg[0] contains an alias to that program, or a symlink, or some other thing I haven't thought of, the function would return /usr/bin/myprog.

I have found a couple of other libraries available on Conan that have this functionality, including Corrade::Utility::Directory::executableLocation() in Corrade (https://github.com/mosra/corrade) and boost::dll::fs::path::program_location() in Boost (https://github.com/boostorg/dll), but it's impossible to install either of them without installing a whole lot of other dependencies that I'm not interested in.

Your library would be a perfect fit for this kind of function: it's very small, and includes a lot of other functions that would be very useful in client code after calling program_location().

I could write the program_location() function for you if you're interested. The implementation is around 5-10 SLOC for each platform you want to target, plus some preprocessor directives. I hate having to copy-paste this code whenever I need it; it really belongs in a library that has a good CI test suite, like yours.

The only tricky part I can foresee is writing cross-platform tests for this function. I think that you would want one process that calls the program_location() function, and another process that can verify the first process' output under different conditions (aliased, symlinked, etc) where argv[0] could get you the wrong answer. I would be tempted to write this in bash script, iff you can do that on Windows.

Please let me know if you're interested. I really like your project.

likle commented 3 years ago

Hi @ddalcino !

Sorry for the late reply, and thank you a lot for your valuable input! Currently cwalk doesn't have any OS dependencies and works in a lot of places, I hesitate because adding such a feature would probably change that. However, I do understand this would be very useful for a lot of people and I am thinking how we could do something like this in future. If you already have an idea how to do this with a nice interface without restricting us to a few operating systems I'd be of course totally open for suggestions!

ddalcino commented 3 years ago

You're right; this addition would add some OS dependencies, since this would be OS-specific code. I have written and tested code that does this for Linux, Mac, and Windows. This stackoverflow answer (https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe#answer-1024937) contains hints on how to do it on Solaris, FreeBSD, NetBSD, and DragonFly BSD; each one is substantially different. I think that if we wanted to provide implementations for the BSDs and Solaris, we would really need CI tests for those platforms. I think you can do that in Travis CI with a docker image.

I understand if you don't want to add this because it would restrict the number of places this project could run; there's a big difference between "everywhere" and "only N operating systems". I would suggest that this particular function should have a note in the documentation describing exactly which operating systems are supported, and use preprocessor macros to prevent the function being defined or prototyped on any unsupported operating systems. We would not want this function to cause a build failure on any platform we don't know about.

I imagine that this function prototype would fit in pretty well with the rest of cwalk:

size_t cwk_path_get_executable_path(char * buffer, size_t buffer_size);

This function would always return the number of bytes written to buffer. In the event that the buffer is too short to hold the entire path, no bytes would be written.

Most of the time, the only error condition would occur when the buffer provided is too short. Theoretically, there are other OS-specific error conditions unrelated to the length of the buffer. Unfortunately, I don't know what those could be, and they could be different on each platform. It may be useful to return an enum that describes the error condition.

kampeador commented 3 years ago

In my opinion it is out of the scope of this project. There is a good dedicated library for this: https://github.com/gpakosz/whereami

ddalcino commented 3 years ago

In my opinion it is out of the scope of this project. There is a good dedicated library for this: https://github.com/gpakosz/whereami

I was unaware of that library, but it looks like it's exactly what I need. Thanks for the info.

I think you're right about this being out of scope; I began to realize that myself when I started looking into testing this function in CI.