Vuo 2.4.4
Loading...
Searching...
No Matches
VuoRuntime.cc
Go to the documentation of this file.
1
10#include <getopt.h>
11#include <mach-o/dyld.h> // for _NSGetExecutablePath()
12#include <dirent.h>
13#include <dlfcn.h>
14
15#include "VuoApp.h"
16#include "VuoEventLoop.h"
17#include "VuoException.hh"
18#include "VuoRuntime.h"
21#include "VuoRuntimeState.hh"
22#include "module.h"
23
24extern "C"
25{
26
28void *vuoRuntimeState = NULL;
29
33void vuoInit(int argc, char **argv)
34{
35 bool doAppInit = false;
36 char *controlURL = NULL;
37 char *telemetryURL = NULL;
38 bool isPaused = false;
39 pid_t runnerPid = 0;
40 int runnerPipe = -1;
41 bool continueIfRunnerDies = false;
42 bool doPrintHelp = false;
43 bool doPrintLicenses = false;
44
45 // parse commandline arguments
46 {
47 int getoptArgC = 0;
48 char **getoptArgV = (char **)malloc(sizeof(char *) * argc);
49 for(int i = 0; i < argc; ++i)
50 {
51 // Don't pass the OS X Process Serial Number argument to getopt, since it can't handle long arguments with a single hyphen.
52 if (strncmp(argv[i], "-psn_", 5) == 0)
53 {
54 // Since we have a process serial number, we can assume this is an exported app being invoked by LaunchServices.
55 // Therefore we need to initialize the app (so it shows up in the dock).
56 doAppInit = true;
57 continue;
58 }
59
60 getoptArgV[getoptArgC++] = argv[i];
61 }
62
63 static struct option options[] = {
64 {"help", no_argument, NULL, 0},
65 {"vuo-control", required_argument, NULL, 0},
66 {"vuo-telemetry", required_argument, NULL, 0},
67 {"vuo-pause", no_argument, NULL, 0},
68 {"vuo-loader", required_argument, NULL, 0},
69 {"vuo-runner-pipe", required_argument, NULL, 0},
70 {"vuo-continue-if-runner-dies", no_argument, NULL, 0},
71 {"vuo-licenses", no_argument, NULL, 0},
72 {"vuo-runner-pid", required_argument, NULL, 0},
73 {NULL, no_argument, NULL, 0}
74 };
75 int optionIndex=-1;
76 int ret;
77 while ((ret = getopt_long(getoptArgC, getoptArgV, "", options, &optionIndex)) != -1)
78 {
79 if (ret == '?')
80 continue;
81
82 switch(optionIndex)
83 {
84 case 0: // --help
85 doPrintHelp = true;
86 break;
87 case 1: // --vuo-control
88 if (controlURL)
89 free(controlURL);
90 controlURL = strdup(optarg);
91 break;
92 case 2: // --vuo-telemetry
93 if (telemetryURL)
94 free(telemetryURL);
95 telemetryURL = strdup(optarg);
96 break;
97 case 3: // --vuo-pause
98 isPaused = true;
99 break;
100 case 4: // --vuo-loader (ignored, but added here to avoid "unrecognized option" warning)
101 break;
102 case 5: // --vuo-runner-pipe
103 runnerPipe = atoi(optarg);
104 break;
105 case 6: // --vuo-continue-if-runner-dies
107 break;
108 case 7: // --vuo-licenses
109 doPrintLicenses = true;
110 break;
111 case 8: // --vuo-runner-pid
112 runnerPid = atoi(optarg);
113 break;
114 default:
115 VUserLog("Error: Unknown option %d.", optionIndex);
116 break;
117 }
118 }
119 free(getoptArgV);
120 }
121
122 // macOS 10.14 no longer provides the `-psn_` argument, so use an alternate method to detect LaunchServices.
123 // launchd is pid 1.
124 if (!doAppInit && !controlURL && getppid() == 1)
125 doAppInit = true;
126
127 // Get the exported executable path.
128 char rawExecutablePath[PATH_MAX+1];
129 uint32_t size = sizeof(rawExecutablePath);
130 _NSGetExecutablePath(rawExecutablePath, &size);
131
132 if (doPrintHelp)
133 {
134 printf("Usage: %s [options]\n"
135 "Options:\n"
136 " --help Display this information.\n"
137 " --vuo-licenses Display license information.\n",
138 argv[0]);
139
140 exit(0);
141 }
142 else if (doPrintLicenses)
143 {
144 printf("This composition may include software licensed under the following terms:\n\n");
145
146 // Derive the path of the app bundle's "Licenses" directory from its executable path.
147 char licensesPath[PATH_MAX+1];
148 licensesPath[0] = 0;
149
150 const char *frameworkPath = VuoGetFrameworkOrRunnerFrameworkPath();
151 if (frameworkPath)
152 {
153 strncpy(licensesPath, frameworkPath, PATH_MAX);
154 strncat(licensesPath, "/Versions/" VUO_FRAMEWORK_VERSION_STRING "/Documentation/Licenses", PATH_MAX);
155 }
156
157 bool foundLicenses = false;
158 if (licensesPath[0] && access(licensesPath, 0) == 0)
159 {
160 DIR *dirp = opendir(licensesPath);
161 struct dirent *dp;
162 while ((dp = readdir(dirp)) != NULL)
163 {
164 if (dp->d_name[0] == '.')
165 continue;
166
167 printf("=== %s =====================================================\n\n",dp->d_name);
168
169 size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
170 char licensePath[pathSize];
171 strlcpy(licensePath, licensesPath, pathSize);
172 strlcat(licensePath, "/", pathSize);
173 strlcat(licensePath, dp->d_name, pathSize);
174
175 int fd = open(licensePath, O_RDONLY);
176 char data[1024];
177 int bytesRead;
178 while((bytesRead = read(fd, data, 1024)) > 0)
179 write(1, data, bytesRead);
180 close(fd);
181
182 printf("\n\n\n");
183 foundLicenses = true;
184 }
185 closedir(dirp);
186 }
187
188 if (!foundLicenses)
189 printf("(No license information found.)\n");
190
191 free(controlURL);
192 free(telemetryURL);
193 exit(0);
194 }
195
196 void *executableHandle = dlopen(rawExecutablePath, 0);
197 if (! executableHandle)
198 {
199 VUserLog("The composition couldn't be started because a handle to the executable couldn't be obtained : %s", dlerror());
200 free(controlURL);
201 free(telemetryURL);
202 return;
203 }
204
206 executableHandle, NULL, doAppInit);
207
208 dlclose(executableHandle);
209
210 free(controlURL);
211 free(telemetryURL);
212}
213
232void vuoInitInProcess(void *ZMQContext, const char *controlURL, const char *telemetryURL, bool isPaused, pid_t runnerPid,
233 int runnerPipe, bool continueIfRunnerDies, const char *workingDirectory,
234 void *compositionBinaryHandle, void *previousRuntimeState, bool doAppInit)
235{
236 runtimeState = (VuoRuntimeState *)previousRuntimeState;
237 if (! runtimeState)
238 {
244 }
245
247
248 VuoCompositionState *compositionState = new VuoCompositionState;
249 compositionState->runtimeState = runtimeState;
250 compositionState->compositionIdentifier = "";
252
253 try
254 {
256 workingDirectory, compositionBinaryHandle);
257 }
258 catch (VuoException &e)
259 {
260 VUserLog("%s", e.what());
261 return;
262 }
263
264 if (doAppInit)
265 {
266 typedef void (*vuoAppInitType)(bool requiresDockIcon);
267 vuoAppInitType vuoAppInit = (vuoAppInitType) dlsym(RTLD_SELF, "VuoApp_init");
268 if (vuoAppInit)
269 vuoAppInit(true);
270 }
271
273
274 // If the composition had a pending call to vuoStopComposition() when it was stopped, call it again.
277
279}
280
288void * vuoFini(void)
289{
291 return (void *)runtimeState;
292}
293
301
307{
308 VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
309 if (r)
311 else
313}
314
319pid_t vuoGetRunnerPid(VuoCompositionState *compositionState)
320{
321 VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
322 if (r)
323 return r->getRunnerPid();
324 else
325 return -1;
326}
327
333{
334 VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
335 if (r)
337}
338
344{
345 VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
346 if (r)
348}
349
355{
356 VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
357 if (r)
359}
360
367{
368 return runtimeState->isStopped();
369}
370
371} // extern "C"