Skip to content

Commit 24cfebf

Browse files
committed
Cross Platform Exe Path
This change integrates the library "whereami" to determine the path of the running executable. See https://github.com/gpakosz/whereami for more details. This allows us to have consistent behavior across all build configurations. I also added a fallback case for when it fails on Linux, to add an additional hint if the proc filesystem is missing. This may be useful to help people attempting to run Tangerine from an improperly configured chroot environment without downgrading to behavior that might be less secure such as using argv 0 as a fallback.
1 parent 47d46ee commit 24cfebf

31 files changed

+2572
-40
lines changed

CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ target_sources(VoxWriter
130130
PUBLIC FILE_SET HEADERS
131131
FILES "third_party/voxwriter/VoxWriter.h")
132132

133+
#######################################################################
134+
## whereami:
135+
136+
add_library(whereami OBJECT "third_party/whereami/src/whereami.c")
137+
target_include_directories(whereami PUBLIC "third_party/whereami/src/")
138+
133139

134140
#######################################################################
135141
##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++##
@@ -151,6 +157,7 @@ target_link_libraries(tangerine PRIVATE
151157
imgui
152158
ImFileDialog
153159
VoxWriter
160+
whereami
154161
tinfo # see https://gitlab.kitware.com/cmake/cmake/-/issues/23236
155162
${CMAKE_THREAD_LIBS_INIT}
156163
${CMAKE_DL_LIBS})

tangerine/installation.cpp

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,52 +14,35 @@
1414
// limitations under the License.
1515

1616
#include "installation.h"
17-
18-
#if !_WIN64
19-
#include <unistd.h>
20-
#endif
17+
#include "whereami.h"
18+
#include <iostream>
2119

2220

23-
TangerinePaths::TangerinePaths(int argc, char* argv[])
21+
StatusCode TangerinePaths::PopulateInstallationPaths()
2422
{
25-
#if _WIN64
26-
// TODO: This is fine for standalone builds, but we will want to do something
27-
// else for future library builds. Maybe GetModuleFileNameW?
28-
ExecutablePath = std::filesystem::absolute(argv[0]);
29-
30-
#elif EMBED_RACKET
31-
ExecutablePath = std::filesystem::path(racket_get_self_exe_path(argv[0]));
32-
33-
#else
3423
{
35-
char* Path = nullptr;
36-
ssize_t PathLength = 0;
37-
ssize_t Allocation = 256;
38-
39-
retry:
40-
Path = (char*)malloc(Allocation);
41-
PathLength = readlink("/proc/self/exe", Path, Allocation - 1);
42-
if (PathLength == (Allocation - 1))
24+
int Length = wai_getExecutablePath(NULL, 0, NULL);
25+
if (Length > -1)
4326
{
27+
char* Path = (char*)malloc(Length + 1);
28+
wai_getExecutablePath(Path, Length, NULL);
29+
Path[Length] = '\0';
30+
ExecutablePath = std::filesystem::path(Path);
4431
free(Path);
45-
Allocation *= 2;
46-
goto retry;
47-
}
48-
49-
if (PathLength < 0)
50-
{
51-
// Possibly in a chroot environment where "/proc" is not available, so fall back to generic approach.
52-
ExecutablePath = std::filesystem::absolute(argv[0]);
5332
}
5433
else
5534
{
56-
Path[PathLength] = 0;
57-
ExecutablePath = std::filesystem::path(Path);
35+
#if !_WIN64
36+
// TODO: Right now our platform coverage is "Windows" and "not Windows == Linux". More nuance may be needed here in the future.
37+
if (!std::filesystem::exists("/proc"))
38+
{
39+
std::cout << "Proc filesystem not found.\n";
40+
}
41+
#endif
42+
std::cout << "Failed to determine Tangerine's filesystem path.\n";
43+
return StatusCode::FAIL;
5844
}
59-
60-
free(Path);
6145
}
62-
#endif
6346

6447
ExecutableDir = ExecutablePath.parent_path();
6548

@@ -75,4 +58,6 @@ TangerinePaths::TangerinePaths(int argc, char* argv[])
7558

7659
ShadersDir = PkgDataDir / std::filesystem::path("shaders");
7760
ModelsDir = PkgDataDir / std::filesystem::path("models");
61+
62+
return StatusCode::PASS;
7863
}

tangerine/installation.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
#pragma once
1717
#include <filesystem>
1818
#include "embedding.h"
19+
#include "errors.h"
1920

2021

2122
struct TangerinePaths
2223
{
23-
TangerinePaths() {}
24-
TangerinePaths(int argc, char* argv[]);
24+
StatusCode PopulateInstallationPaths();
2525

2626
std::filesystem::path ExecutablePath;
2727
std::filesystem::path ExecutableDir;

tangerine/tangerine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,7 @@ SDL_GLContext Context = nullptr;
17941794

17951795
StatusCode Boot(int argc, char* argv[])
17961796
{
1797-
Installed = TangerinePaths(argc, argv);
1797+
RETURN_ON_FAIL(Installed.PopulateInstallationPaths());
17981798
LastOpenDir = Installed.ModelsDir;
17991799
LoadBookmarks();
18001800

third_party/licenses.inl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,19 @@ if (ImGui::BeginTabItem("voxwriter"))
9090
ImGui::EndTabItem();
9191
}
9292
#endif
93+
94+
#if 1
95+
if (ImGui::BeginTabItem("whereami"))
96+
{
97+
ImGui::TextUnformatted("MIT License\n\nCopyright Gregory Pakosz\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", nullptr);
98+
ImGui::EndTabItem();
99+
}
100+
#endif
101+
102+
#if 1
103+
if (ImGui::BeginTabItem("whereami"))
104+
{
105+
ImGui::TextUnformatted("--------------------------------------------------------------------------------\n DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n Version 2, December 2004\n\n Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\n\n Everyone is permitted to copy and distribute verbatim or modified\n copies of this license document, and changing it is allowed as long\n as the name is changed.\n\n DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n 0. You just DO WHAT THE FUCK YOU WANT TO.\n 1. Bla bla bla\n 2. Montesqieu et camembert, vive la France, zut alors!\n\n--------------------------------------------------------------------------------\n\nWTFPLv2 is very permissive, see http://www.wtfpl.net/faq/\n\nHowever, if this WTFPLV2 is REALLY a blocker and is the reason you can't use\nthis project, contact me and I'll dual license it.\n\n--------------------------------------------------------------------------------\n", nullptr);
106+
ImGui::EndTabItem();
107+
}
108+
#endif

third_party/whereami/LICENSE.MIT

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
MIT License
2+
3+
Copyright Gregory Pakosz
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--------------------------------------------------------------------------------
2+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3+
Version 2, December 2004
4+
5+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
6+
7+
Everyone is permitted to copy and distribute verbatim or modified
8+
copies of this license document, and changing it is allowed as long
9+
as the name is changed.
10+
11+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
12+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13+
14+
0. You just DO WHAT THE FUCK YOU WANT TO.
15+
1. Bla bla bla
16+
2. Montesqieu et camembert, vive la France, zut alors!
17+
18+
--------------------------------------------------------------------------------
19+
20+
WTFPLv2 is very permissive, see http://www.wtfpl.net/faq/
21+
22+
However, if this WTFPLV2 is REALLY a blocker and is the reason you can't use
23+
this project, contact me and I'll dual license it.
24+
25+
--------------------------------------------------------------------------------

third_party/whereami/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Where Am I?
2+
3+
A drop-in two files library to locate the current executable and the current
4+
module on the file system.
5+
6+
Supported platforms:
7+
8+
- Windows
9+
- Linux
10+
- Mac
11+
- iOS
12+
- Android
13+
- QNX Neutrino
14+
- FreeBSD
15+
- NetBSD
16+
- DragonFly BSD
17+
- SunOS
18+
- OpenBSD
19+
20+
Just drop `whereami.h` and `whereami.c` into your build and get started. (see
21+
also [customizing compilation])
22+
23+
[customizing compilation]: #customizing-compilation
24+
25+
--------------------------------------------------------------------------------
26+
27+
## Usage
28+
29+
- `wai_getExecutablePath()` returns the path of the enclosing executable
30+
- `wai_getModulePath()` returns the path of the enclosing module
31+
32+
Example usage:
33+
34+
- first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to retrieve
35+
the length of the path
36+
- allocate the destination buffer with `path = (char*)malloc(length + 1);`
37+
- call `wai_getExecutablePath(path, length, &dirname_length)` again to retrieve
38+
the path
39+
- add a terminal `NUL` character with `path[length] = '\0';`
40+
41+
Here is the output of the example:
42+
43+
$ make -j -C _gnu-make
44+
$ cp ./bin/mac-x86_64/library.dylib /tmp/
45+
$ ./bin/mac-x86_64/executable --load-library=/tmp/library.dylib
46+
47+
executable path: /Users/gregory/Projects/whereami/bin/mac-x86_64/executable
48+
dirname: /Users/gregory/Projects/whereami/bin/mac-x86_64
49+
basename: executable
50+
module path: /Users/gregory/Projects/whereami/bin/mac-x86_64/executable
51+
dirname: /Users/gregory/Projects/whereami/bin/mac-x86_64
52+
basename: executable
53+
54+
library loaded
55+
executable path: /Users/gregory/Projects/whereami/bin/mac-x86_64/executable
56+
dirname: /Users/gregory/Projects/whereami/bin/mac-x86_64
57+
basename: executable
58+
module path: /private/tmp/library.dylib
59+
dirname: /private/tmp
60+
basename: library.dylib
61+
library unloaded
62+
63+
--------------------------------------------------------------------------------
64+
65+
## Customizing compilation
66+
67+
You can customize the library's behavior by defining the following macros:
68+
69+
- `WAI_FUNCSPEC`
70+
- `WAI_PREFIX`
71+
- `WAI_MALLOC`
72+
- `WAI_REALLOC`
73+
- `WAI_FREE`
74+
75+
## Compiling for Windows
76+
77+
There is a Visual Studio 2015 solution in the `_win-vs14/` folder.
78+
79+
## Compiling for Linux or Mac
80+
81+
There is a GNU Make 3.81 `MakeFile` in the `_gnu-make/` folder:
82+
83+
$ make -j -C _gnu-make/
84+
85+
## Compiling for Mac
86+
87+
See above if you want to compile from command line. Otherwise there is an Xcode
88+
project located in the `_mac-xcode/` folder.
89+
90+
## Compiling for iOS
91+
92+
There is an Xcode project located in the `_ios-xcode/` folder.
93+
94+
If you prefer compiling from command line and deploying to a jailbroken device
95+
through SSH, use:
96+
97+
$ make -j -C _gnu-make/ binsubdir=ios CC="$(xcrun --sdk iphoneos --find clang) -isysroot $(xcrun --sdk iphoneos --show-sdk-path) -arch armv7 -arch armv7s -arch arm64" postbuild="codesign -s 'iPhone Developer'"
98+
99+
## Compiling for Android
100+
101+
You will have to install the Android NDK, and point the `$NDK_ROOT` environment
102+
variable to the NDK path: e.g. `export NDK_ROOT=/opt/android-ndk` (without a
103+
trailing `/` character).
104+
105+
Next, the easy way is to make a standalone Android toolchain with the following
106+
command:
107+
108+
$ $NDK_ROOT/build/tools/make_standalone_toolchain.py --arch=arm64 --api 21 --install-dir=/tmp/android-toolchain
109+
110+
Now you can compile the example by running:
111+
112+
$ make -j -C _gnu-make/ platform=android architecture=arm64 CC=/tmp/android-toolchain/bin/aarch64-linux-android-gcc CXX=/tmp/android-toolchain/bin/aarch64-linux-android-g++
113+
114+
Loading page aligned library straight from APKs is supported. To test, use the
115+
following:
116+
117+
$ zip -Z store app bin/android/library.so
118+
$ zipalign -v -f -p 4 ./app.zip ./app.apk
119+
120+
Then copy `bin/android/executable` and `app.apk` to your Android device and
121+
there launch:
122+
123+
$ ./executable --load-library=$PWD/app.apk!/bin/android/library.so

0 commit comments

Comments
 (0)