···138138#add_subdirectory(external/corecrypto)
139139#add_subdirectory(external/security) # work in progress
140140add_subdirectory(sandbox)
141141+add_subdirectory(xcselect)
141142#add_subdirectory(Cocoa)
142143143144add_subdirectory(external/file/file)
···11+* Implement `xcode-select`
22+* Integrate `man` so that it refers to `libxcselect.dylib` for man paths
33+* Stub out tons of Apple private frameworks to have `xcodebuild` working
44+
+268
src/xcselect/libxcselect.c
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2017 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+#include <stdlib.h>
2020+#include <fcntl.h>
2121+#include <unistd.h>
2222+#include <stdbool.h>
2323+#include <sys/stat.h>
2424+#include <stdlib.h>
2525+#include <errno.h>
2626+#include <string.h>
2727+#include <dlfcn.h>
2828+#include <stdio.h>
2929+#include "libxcselect.h"
3030+3131+static char path_buffer[1024];
3232+3333+static const char* get_developer_dir_from_file(const char* file)
3434+{
3535+ int fd = open(file, O_RDONLY);
3636+ if (fd == -1)
3737+ return NULL;
3838+3939+ int len = read(fd, path_buffer, sizeof(path_buffer)-1);
4040+ if (len <= 0)
4141+ {
4242+ close(fd);
4343+ return NULL;
4444+ }
4545+4646+ path_buffer[len] = 0;
4747+ close(fd);
4848+4949+ return path_buffer;
5050+}
5151+5252+const char* get_developer_dir_from_symlink(const char* link)
5353+{
5454+ ssize_t len;
5555+5656+ len = readlink(link, path_buffer, sizeof(path_buffer)-1);
5757+ if (len <= 0)
5858+ return NULL;
5959+6060+ path_buffer[len] = 0;
6161+ return path_buffer;
6262+}
6363+6464+static bool dir_exists(const char* dir)
6565+{
6666+ struct stat st;
6767+6868+ if (stat(dir, &st) != 0)
6969+ return false;
7070+7171+ return S_ISDIR(st.st_mode);
7272+}
7373+7474+static bool valid_dev_path(const char* path)
7575+{
7676+ char buffer[1024];
7777+ size_t length;
7878+7979+ strcpy(buffer, path);
8080+ strcat(buffer, "/");
8181+8282+ length = strlen(buffer);
8383+ strcat(buffer, "usr/lib/libxcrun.dylib");
8484+ if (access(buffer, F_OK) == 0)
8585+ return true;
8686+8787+ buffer[length] = 0;
8888+ strcat(buffer, "usr/bin/xcrun");
8989+ if (access(buffer, F_OK) == 0)
9090+ return true;
9191+9292+ return false;
9393+}
9494+9595+const char* xcselect_find_developer_contents_from_path(const char* p, bool* is_cmd_line)
9696+{
9797+ size_t length;
9898+9999+ if (*p != '/')
100100+ {
101101+ getcwd(path_buffer, sizeof(path_buffer));
102102+ strcat(path_buffer, "/");
103103+ strcat(path_buffer, p);
104104+ }
105105+ else
106106+ strcpy(path_buffer, p);
107107+108108+ length = strlen(path_buffer);
109109+ if (valid_dev_path(path_buffer))
110110+ return path_buffer;
111111+112112+ path_buffer[length++] = '/';
113113+ path_buffer[length] = 0;
114114+115115+ strcat(path_buffer, "Library/Developer/CommandLineTools");
116116+ if (valid_dev_path(path_buffer))
117117+ {
118118+ *is_cmd_line = true;
119119+ return path_buffer;
120120+ }
121121+122122+ path_buffer[length] = 0;
123123+ strcat(path_buffer, "CommandLineTools");
124124+ if (valid_dev_path(path_buffer))
125125+ {
126126+ *is_cmd_line = true;
127127+ return path_buffer;
128128+ }
129129+130130+ path_buffer[length] = 0;
131131+ strcat(path_buffer, "Contents/Developer");
132132+ if (valid_dev_path(path_buffer))
133133+ return path_buffer;
134134+135135+ return NULL;
136136+}
137137+138138+const char* xcselect_get_developer_dir_path(bool* is_cmd_line)
139139+{
140140+ const char* p;
141141+ char* slash;
142142+143143+ *is_cmd_line = false;
144144+145145+ p = getenv("DEVELOPER_DIR");
146146+ if (p)
147147+ {
148148+ p = xcselect_find_developer_contents_from_path(p, is_cmd_line);
149149+ if (p)
150150+ goto have_path;
151151+ }
152152+153153+ p = get_developer_dir_from_symlink("/var/db/xcode_select_link");
154154+ if (p)
155155+ goto have_path;
156156+157157+ p = get_developer_dir_from_symlink("/usr/share/xcode-select/xcode_dir_link");
158158+ if (p)
159159+ goto have_path;
160160+161161+ p = get_developer_dir_from_file("/usr/share/xcode-select/xcode_dir_path");
162162+ if (p)
163163+ goto have_path;
164164+165165+ if (dir_exists("/Applications/Xcode.app"))
166166+ {
167167+ p = "/Applications/Xcode.app/Contents/Developer";
168168+ goto have_path;
169169+ }
170170+ else if (dir_exists("/Library/Developer/CommandLineTools"))
171171+ {
172172+ p = "/Library/Developer/CommandLineTools";
173173+ goto have_path;
174174+ }
175175+176176+ return NULL;
177177+178178+have_path:
179179+ slash = strrchr(p, '/');
180180+ if (slash != NULL)
181181+ {
182182+ if (strcmp(slash+1, "CommandLineTools") == 0)
183183+ *is_cmd_line = true;
184184+ }
185185+186186+ return p;
187187+}
188188+189189+190190+int xcselect_invoke_xcrun(const char* tool, int argc, char* argv[], int flags)
191191+{
192192+ const char* dev_dir;
193193+ bool is_cmdline;
194194+195195+ dev_dir = xcselect_get_developer_dir_path(&is_cmdline);
196196+197197+ if (dev_dir != NULL)
198198+ {
199199+ char* buf = (char*) malloc(2048);
200200+ size_t length;
201201+ void* lib;
202202+203203+ if (is_cmdline && (flags & XCSELECT_FLAG_REQUIRE_XCODE))
204204+ {
205205+ fprintf(stderr, "xcrun: tool '%s' requires Xcode installation, command line tools are insufficient.\n", tool);
206206+ exit(1);
207207+ }
208208+209209+ strcpy(buf, dev_dir);
210210+ strcat(buf, "/");
211211+ length = strlen(buf);
212212+213213+ strcat(buf, "usr/lib/libxcrun.dylib");
214214+ lib = dlopen(buf, RTLD_LAZY);
215215+216216+ if (lib != NULL)
217217+ {
218218+ void(*fn)(const char*, int, char**, const char*);
219219+220220+ *((void**)&fn) = dlsym(lib, "xcrun_main");
221221+ if (!fn)
222222+ {
223223+ fprintf(stderr, "xcrun: broken libxcrun.dylib at '%s'\n", buf);
224224+ }
225225+ else
226226+ {
227227+ fn(getprogname(), argc, argv, dev_dir);
228228+ }
229229+ }
230230+ else
231231+ {
232232+ char** argv2;
233233+ int j = 0;
234234+235235+ buf[length] = 0;
236236+ strcat(buf, "usr/bin/xcrun");
237237+238238+ argv2 = (char**) __builtin_alloca((argc+2) * sizeof(char*));
239239+ argv2[j++] = buf;
240240+241241+ if (tool != NULL)
242242+ argv2[j++] = (char*) tool;
243243+244244+ for (int i = 0; i < argc; i++, j++)
245245+ argv2[j] = argv[i];
246246+247247+ execv(buf, argv2);
248248+ fprintf(stderr, "xcrun: developer path '%s' is invalid, failed to execute '%s': %s\n",
249249+ dev_dir, buf, strerror(errno));
250250+ }
251251+ }
252252+ else if (dir_exists("/usr/libexec/DeveloperTools") && tool != NULL)
253253+ {
254254+ char* buf = __builtin_alloca(strlen(tool) + 30);
255255+ strcpy(buf, "/usr/libexec/DeveloperTools/");
256256+ strcat(buf, tool);
257257+258258+ execv(buf, argv);
259259+ fprintf(stderr, "xcrun: failed to exec '%s': %s\n", buf, strerror(errno));
260260+ }
261261+ else
262262+ {
263263+ fprintf(stderr, "xcrun: cannot find developer tools, set DEVELOPER_DIR if you are using a non-standard location.\n");
264264+ }
265265+266266+ exit(1);
267267+}
268268+
+27
src/xcselect/libxcselect.h
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2017 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+#ifndef _LIBXCSELECT_H_
2020+#define _LIBXCSELECT_H_
2121+2222+#define XCSELECT_FLAG_REQUIRE_XCODE 1
2323+2424+int xcselect_invoke_xcrun(const char* tool, int argc, char* argv[], int flags);
2525+2626+#endif
2727+
+27
src/xcselect/xcrun-shim.c
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2017 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+#include "libxcselect.h"
2020+#include <stdlib.h>
2121+#include <string.h>
2222+2323+int main(int argc, const char** argv)
2424+{
2525+ return xcselect_invoke_xcrun(TOOL_NAME, argc - 1, &argv[1], 0);
2626+}
2727+
+38
src/xcselect/xcrun.c
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2017 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+#include "libxcselect.h"
2020+#include <stdlib.h>
2121+#include <string.h>
2222+2323+int main(int argc, const char** argv)
2424+{
2525+ const char* tool;
2626+ const char* pname = getprogname();
2727+2828+ if (*pname == '/')
2929+ tool = pname + 1;
3030+ else
3131+ tool = pname;
3232+3333+ if (strcasecmp(tool, "xcrun") == 0)
3434+ tool = NULL;
3535+3636+ return xcselect_invoke_xcrun(tool, argc - 1, &argv[1], 0);
3737+}
3838+