1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#import <Cocoa/Cocoa.h>
static int
check_mono_version (const char *version, const char *req_version)
{
char *req_end, *end;
long req_val, val;
while (*req_version && *version) {
req_val = strtol (req_version, &req_end, 10);
if (req_version == req_end || (*req_end && *req_end != '.')) {
NSLog (@"Bad version requirement string '%s'", req_end);
return FALSE;
}
val = strtol (version, &end, 10);
if (version == end || val < req_val)
return FALSE;
if (val > req_val) {
return TRUE;
}
if (*req_end == '.' && *end != '.')
return FALSE;
req_version = req_end;
if (*req_version)
req_version++;
version = end + 1;
}
return TRUE;
}
static NSString *
xcode_get_dev_path ()
{
NSString *xcode_link = [[NSFileManager defaultManager]
destinationOfSymbolicLinkAtPath:@"/var/db/xcode_select_link"
error:nil
];
return xcode_link ?: @"/Applications/Xcode.app/Contents/Developer";
}
static NSArray<NSString *> *
generate_fallback_paths (NSString *binDir)
{
NSString *lib_path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"lib"];
return @[
/* Inject our Resources/lib and bin dirs dir */
binDir,
lib_path,
/* Add Xcode's CommandLineTools dev lib dir before Xcode's Developer dir */
@"/Library/Developer/CommandLineTools/usr/lib",
/* Add Xcode's dev lib dir into the DYLD_FALLBACK_LIBRARY_PATH */
xcode_get_dev_path(),
/* Add Mono's lib dir */
@"/Library/Frameworks/Mono.framework/Libraries",
@"/usr/lib",
@"/usr/local/lib",
];
}
static bool
push_env (const char *variable, const char *value, BOOL push_to_end)
{
const char *current;
size_t len;
char *buf;
BOOL updated = YES;
if ((current = getenv (variable)) && *current) {
char *token, *copy, *tofree;
size_t current_length;
tofree = copy = strdup (current);
current_length = strlen (current);
len = strlen (value);
while ((token = strsep(©, ":"))) {
if (!strncmp (token, value, len)) {
while ((strsep(©, ":")))
continue;
updated = NO;
goto done;
}
}
if (!(buf = (char *)malloc (len + current_length + 2)))
return NO;
if (push_to_end) {
memcpy (buf, current, current_length);
buf[current_length] = ':';
strcpy (buf + current_length + 1, value);
} else {
memcpy (buf, value, len);
buf[len] = ':';
strcpy (buf + len + 1, current);
}
setenv (variable, buf, 1);
free (buf);
done:
free (tofree);
} else {
setenv (variable, value, 1);
}
return updated;
}
static bool
push_env_to_start (const char *variable, const char *value)
{
return push_env (variable, value, NO);
}
static bool
push_env_to_end (const char *variable, const char *value)
{
return push_env (variable, value, YES);
}
static bool
replace_env (const char *variable, const char *value)
{
const char *old = getenv (variable);
if (old && !strcmp (old, value))
return false;
setenv (variable, value, true);
return true;
}
static bool
update_environment (NSString *binDir)
{
NSArray<NSString *> *array;
bool updated = NO;
NSString *value;
if ((array = generate_fallback_paths (binDir))) {
for (value in array) {
if (push_env_to_end ("DYLD_FALLBACK_LIBRARY_PATH", [value UTF8String]))
updated = YES;
}
}
if (push_env_to_start ("PKG_CONFIG_PATH", "/Library/Frameworks/Mono.framework/External/pkgconfig"))
updated = YES;
NSBundle *bundle = [NSBundle mainBundle];
NSString *resourcePath = [bundle resourcePath];
/* Enable the use of stuff bundled into the app bundle and the Mono "External" directory */
value = [resourcePath stringByAppendingPathComponent:@"lib/pkgconfig"];
if (push_env_to_start ("PKG_CONFIG_PATH", [value UTF8String])) {
updated = YES;
}
value = [[bundle executablePath] stringByDeletingLastPathComponent];
if (push_env_to_start ("PATH", [value UTF8String]))
updated = YES;
if (push_env_to_start ("MONO_GAC_PREFIX", [resourcePath UTF8String]))
updated = YES;
// Note: older versions of Xamarin Studio incorrectly set the PATH to the Resources dir instead of the MacOS dir
// and older versions of mtouch relied on this broken behavior.
if (push_env_to_start ("PATH", [resourcePath UTF8String]))
updated = YES;
if (push_env_to_start ("PATH", "/Library/Frameworks/Mono.framework/Commands"))
updated = YES;
if (push_env_to_end ("PATH", "/usr/local/bin"))
updated = YES;
if (push_env_to_end ("PATH", "~/.dotnet/tools"))
updated = YES;
if (replace_env ("MONODEVELOP_64BIT_SAFE", "yes"))
updated = YES;
if (replace_env ("LC_NUMERIC", "C"))
updated = YES;
return updated;
}
|