Skip to content

Commit dfccb84

Browse files
authored
Merge pull request #27 from matyalatte/unix_support
Unix support
2 parents 764cb44 + 0f043a8 commit dfccb84

17 files changed

+212
-33
lines changed

docs/Build-on-Other.md

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Building Workflow for Other Platforms
2+
3+
You can build tuw on other Unix-like systems, not only Linux.
4+
The workflow is the same as Linux.
5+
6+
## Requirements
7+
8+
- C++ compiler
9+
- GTK+ 3.10 or later
10+
- Ninja
11+
- [Meson](https://github.com/mesonbuild/meson) (**0.58** or later)
12+
- bash
13+
- Shell scripts in [`./Tuw/shell_scripts`](../shell_scripts)
14+
15+
## FreeBSD
16+
17+
On FreeBSD, You can get all the required tools with `pkg`.
18+
19+
```shell
20+
pkg install git bash pkgconf meson ninja
21+
git clone https://github.com/matyalatte/tuw.git
22+
cd tuw
23+
bash shell_scripts/build.sh
24+
./build/Release/Tuw
25+
```
26+
27+
## OpenBSD
28+
29+
On OpenBSD, You can get all the required tools with `pkg_add`.
30+
31+
```shell
32+
pkg_add bash meson ninja
33+
git clone https://github.com/matyalatte/tuw.git
34+
cd tuw
35+
bash shell_scripts/build.sh
36+
./build/Release/Tuw
37+
```
38+
39+
## NetBSD
40+
41+
On NetBSD, You can get all the required tools with `pkgin`.
42+
43+
```shell
44+
pkgin in git mozilla-rootcerts-openssl bash pkgconf meson ninja
45+
git clone https://github.com/matyalatte/tuw.git
46+
cd tuw
47+
bash shell_scripts/build.sh
48+
./build/Release/Tuw
49+
```
50+
51+
If you get linker errors, try to disalble LTO with `b_lto = false` in `./presets/release.ini`.
52+
53+
## Haiku
54+
55+
On Haiku, You can get all the required tools with `pkgman`.
56+
57+
```shell
58+
pkgman install meson ninja gtk3_devel
59+
git clone https://github.com/matyalatte/tuw.git
60+
cd tuw
61+
bash shell_scripts/build.sh
62+
./build/Release/Tuw
63+
```
64+
65+
> [!WARNING]
66+
> Note that GTK on Haiku is still a WIP project.
67+
> Some features might not work properly.
68+
> As far as I know, drag-drop events are not supported yet.
69+
70+
You can also use [the Haiku theme for GTK](https://github.com/B00merang-Project/Haiku) if you don't like the default theme.
71+
72+
```
73+
mkdir -p /boot/home/config/non-packaged/data/themes
74+
cd /boot/home/config/non-packaged/data/themes
75+
git clone https://github.com/B00merang-Project/Haiku.git
76+
77+
# replace `gtk-theme='Adwaita'` with `gtk-theme='Haiku'`
78+
nano /boot/system/non-packaged/data/glib-2.0/schemas/00_org.gnome.desktop.interface.gschema.override
79+
80+
glib-compile-schemas /boot/system/non-packaged/data/glib-2.0/schemas
81+
```

docs/Building.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ You can build it on the following platforms.
77

88
- Windows 7 or later
99
- macOS 10.9 or later
10-
- Linux with GTK+ 3.10 or later
10+
- Unix with GTK+ 3.10 or later
1111

1212
You can also see the list of tested platforms [here](./Test-Env.md).
1313

@@ -18,6 +18,7 @@ There are platform-specific documents for building the executable with [Meson](h
1818
- [Building Workflow for Windows](./Build-on-Windows.md)
1919
- [Building Workflow for macOS](./Build-on-Mac.md)
2020
- [Building Workflow for Linux](./Build-on-Linux.md)
21+
- [Building Workflow for Other Platforms](./Build-on-Other.md)
2122

2223
You can also see [batch files](../batch_files/) and [shell scripts](../shell_scripts/) to understand the workflow.
2324

docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ All you need is a JSON file and a tiny executable.
2929
- [Embed JSON into exe](../examples/get_start/json_embed/)
3030
- Save arguments
3131
- Input paths by drag and drop
32-
- Cross-platform
32+
- Cross-platform (Windows, macOS, Linux, BSD, etc.)
3333
- Native look and feel
3434
- Portable
3535
- Small size

docs/Test-Env.md

+4
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ Here is the list of test environments.
2222
| Alpine3.16 | x64 | gcc | musl | :heavy_check_mark: | :x: | :heavy_check_mark: |
2323
| Alpine3.16 | arm64 | gcc | musl | :heavy_check_mark: | :x: | :heavy_check_mark: |
2424
| Alpine3.18 | x64 | | musl | :x: | :warning: | :x: |
25+
| FreeBSD14.0 | x64 | gcc | | :warning: | :warning: | :warning: |
26+
| OpenBSD7.4 | x64 | clang | | :warning: | :warning: | :warning: |
27+
| NetBSD9.3 | x64 | gcc | | :warning: | :warning: | :warning: |
28+
| Haiku R1/beta4 | x64 | gcc | | :warning: | :warning: | :x: |

docs/changelog.txt

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
ver 0.6.3
2+
- Supported Unix-like systems (FreeBSD, Haiku, etc).
3+
- Added URL validation for safety.
4+
(You can not open help URLs contain some special characters.)
5+
16
ver 0.6.2
27
- Fixed typos.
38
- Fixed a bug that the menu can be empty on macOS.

include/main_frame.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class MainFrame {
1313
int m_definition_id;
1414
rapidjson::Document m_config;
1515
uiWindow* m_mainwin;
16+
#ifdef __TUW_UNIX__
17+
uiWindow* m_logwin;
18+
#endif
1619

1720
std::vector<Component*> m_components;
1821
uiGrid* m_grid;
@@ -40,8 +43,12 @@ class MainFrame {
4043
void SaveConfig();
4144
void Fit();
4245
void Close() {
43-
if (m_mainwin == NULL) return;
44-
uiControlDestroy(uiControl(m_mainwin));
46+
if (m_mainwin != NULL)
47+
uiControlDestroy(uiControl(m_mainwin));
48+
#ifdef __TUW_UNIX__
49+
if (m_logwin != NULL)
50+
uiControlDestroy(uiControl(m_logwin));
51+
#endif
4552
}
4653
int IsSafeMode() { return uiMenuItemChecked(m_menu_item); }
4754
};

include/string_utils.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ uint32_t Fnv1Hash32(const std::string& str);
88
std::string UTF16toUTF8(const wchar_t* str);
99
std::wstring UTF8toUTF16(const char* str);
1010
void PrintFmt(const char* fmt, ...);
11-
#elif defined(__linux__)
11+
#elif defined(__TUW_UNIX__)
1212
void SetLogEntry(void* log_entry);
1313
void PrintFmt(const char* fmt, ...);
1414
#else

include/tuw_constants.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ namespace tuw_constants {
1010
" CLI tools\n";
1111
constexpr char TOOL_NAME[] = "Tuw";
1212
constexpr char AUTHOR[] = "matyalatte";
13-
constexpr char VERSION[] = "0.6.2";
14-
constexpr int VERSION_INT = 602;
13+
constexpr char VERSION[] = "0.6.3";
14+
constexpr int VERSION_INT = 603;
1515

1616
#ifdef _WIN32
1717
constexpr char OS[] = "win";
@@ -22,7 +22,7 @@ namespace tuw_constants {
2222
const int BOX_CHECKS_SPACE = 0;
2323
const int BTN_WIDTH = 90;
2424
const int BTN_HEIGHT = 24;
25-
#elif defined(__linux__)
25+
#elif defined(__TUW_UNIX__)
2626
constexpr char OS[] = "linux";
2727
const int GRID_COMP_XSPACE = 4;
2828
const int GRID_MAIN_SPACE = 12;

meson.build

+5-3
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ elif tuw_OS == 'darwin'
7777
warning('This project has NOT been tested with your compiler. (' + tuw_compiler + ')')
7878
endif
7979
else
80-
if tuw_OS != 'linux'
81-
warning('This OS is unsupported. (' + tuw_OS + ')')
80+
if tuw_OS == 'haiku'
81+
tuw_link_args += ['-lbe']
82+
tuw_cpp_args += ['-D__TUW_HAIKU__']
8283
endif
8384
tuw_link_args += ['-no-pie']
85+
tuw_cpp_args += ['-D__TUW_UNIX__']
8486
if tuw_compiler != 'gcc'
8587
warning('This project has NOT been tested with your compiler. (' + tuw_compiler + ')')
8688
endif
@@ -98,7 +100,7 @@ if tuw_OS != 'windows'
98100
tuw_cpp_args += ['-ffunction-sections', '-fdata-sections']
99101
if tuw_compiler == 'gcc'
100102
tuw_link_args += ['-Wl,--gc-sections']
101-
elif tuw_compiler.startswith('clang')
103+
elif tuw_compiler.startswith('clang') and tuw_OS == 'darwin'
102104
tuw_link_args += ['-Wl,-dead_strip']
103105
endif
104106
endif

src/env_utils.cpp

+70-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212
#ifdef __APPLE__
1313
#include <mach-o/dyld.h>
1414
#endif
15+
#ifdef __FreeBSD__
16+
#include <sys/param.h>
17+
#include <sys/sysctl.h> // for GetExecutablePathFreeBSD()
18+
#endif
19+
#ifdef __TUW_HAIKU__
20+
#include <kernel/image.h> // for GetExecutablePathHaiku()
21+
#endif
1522
#include <sys/stat.h>
1623
#include <unistd.h>
1724
#include <pwd.h>
@@ -99,25 +106,79 @@ namespace env_utils {
99106
}
100107
}
101108

109+
#ifdef __TUW_UNIX__
110+
#ifdef __FreeBSD__
111+
// FreeBSD requires sysctl to get the executable path.
112+
void GetExecutablePathFreeBSD(char *path) {
113+
size_t path_size = PATH_MAX;
114+
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
115+
int error = sysctl(mib, 4, path, &path_size, NULL, 0);
116+
if (error < 0 || path_size == 0)
117+
path_size = 0;
118+
path[path_size] = 0;
119+
}
120+
102121
std::string GetExecutablePath() {
103122
char path[PATH_MAX + 1];
104123
path[PATH_MAX] = 0;
105-
#ifdef __linux__
106-
const size_t LINKSIZE = 100;
107-
char link[LINKSIZE];
108-
snprintf(link, LINKSIZE, "/proc/%d/exe", getpid() );
109-
int path_size = readlink(link, path, PATH_MAX);
110-
if (path_size == -1)
111-
path_size = 0;
124+
GetExecutablePathFreeBSD(path);
125+
if (path[0] == 0)
126+
return "/";
127+
return path;
128+
}
129+
#elif defined(__TUW_HAIKU__)
130+
// Haiku OS requires its own API to get the executable path.
131+
std::string GetExecutablePath() {
132+
int32_t cookie = 0;
133+
image_info info;
134+
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
135+
if (info.type == B_APP_IMAGE)
136+
return info.name;
137+
}
138+
return "/";
139+
}
140+
#else
141+
// Linux distributons support readlink to get the executable path.
142+
int TryReadlink(const char *link, char *path, int path_size) {
143+
int new_path_size;
144+
if (path_size != 0)
145+
return path_size;
146+
new_path_size = readlink(link, path, PATH_MAX);
147+
if (new_path_size == -1)
148+
new_path_size = 0;
149+
return new_path_size;
150+
}
151+
152+
void GetExecutablePathUnix(char *path) {
153+
int path_size = 0;
154+
path_size = TryReadlink("/proc/self/exe", path, path_size); // Linux
155+
path_size = TryReadlink("/proc/curproc/exe", path, path_size); // NetBSD
156+
path_size = TryReadlink("/proc/curproc/file", path, path_size); // OpenBSD
112157
path[path_size] = 0;
113-
#else
158+
}
159+
160+
std::string GetExecutablePath() {
161+
char path[PATH_MAX + 1];
162+
path[PATH_MAX] = 0;
163+
GetExecutablePathUnix(path);
164+
if (path[0] == 0)
165+
return "/";
166+
return path;
167+
}
168+
#endif
169+
#endif // __TUW_UNIX__
170+
171+
#ifdef __APPLE__
172+
std::string GetExecutablePath() {
173+
char path[PATH_MAX + 1];
174+
path[PATH_MAX] = 0;
114175
uint32_t bufsize = PATH_MAX;
115176
_NSGetExecutablePath(path, &bufsize);
116-
#endif
117177
if (path[0] == 0)
118178
return "/";
119179
return path;
120180
}
181+
#endif
121182

122183
bool FileExists(const std::string& path) {
123184
struct stat buffer;

src/exec.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ ExecuteResult LaunchDefaultApp(const std::string& url) {
134134
#ifdef _WIN32
135135
std::wstring utf16_url = UTF8toUTF16(url.c_str());
136136
const wchar_t* argv[] = {L"cmd.exe", L"/c", L"start", utf16_url.c_str(), NULL};
137-
#elif defined(__linux__)
137+
#elif defined(__TUW_UNIX__) && !defined(__TUW_HAIKU__)
138+
// Linux and BSD
138139
const char* argv[] = {"xdg-open", url.c_str(), NULL};
139140
#else
141+
// macOS and Haiku OS
140142
const char* argv[] = {"open", url.c_str(), NULL};
141143
#endif
142144
struct subprocess_s process;

src/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ int main_app() {
2525
return 1;
2626
}
2727

28-
#ifdef __linux__
28+
#ifdef __TUW_UNIX__
2929
// Need this for uiMainStep(1)
3030
uiMainSteps();
3131
#endif

0 commit comments

Comments
 (0)