jruby-launcher 1.1.1-java → 1.1.2-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/argnames.h CHANGED
@@ -1,35 +1,35 @@
1
- /*
2
- * Copyright 2009-2010 JRuby Team (www.jruby.org).
3
- */
4
-
5
- #ifndef _ARGNAMES_H
6
- #define _ARGNAMES_H
7
-
8
- /* Standard Java classpath options */
9
- #define ARG_NAME_CP "-J-cp"
10
- #define ARG_NAME_CLASSPATH "-J-classpath"
11
-
12
- /* These are windows-launcher-specific args. They should be prefixed with -X
13
- so that they don't clash with normal Ruby args (like --trace for Rake). */
14
- #define ARG_NAME_SEPAR_PROC "-Xfork-java"
15
- #define ARG_NAME_CONSOLE "-Xconsole"
16
- #define ARG_NAME_LAUNCHER_LOG "-Xtrace"
17
- #define ARG_NAME_BOOTCLASS "-Xbootclass"
18
- #define ARG_NAME_JDKHOME "-Xjdkhome"
19
- #define ARG_NAME_CP_PREPEND "-Xcp:p"
20
- #define ARG_NAME_CP_APPEND "-Xcp:a"
21
- #define ARG_NAME_CMD_ONLY "-Xcommand"
22
- #define ARG_NAME_NO_BOOTCLASSPATH "-Xnobootclasspath"
23
-
24
- /* Below are standard JRuby args handled by the launcher. */
25
- #define ARG_NAME_SERVER "--server"
26
- #define ARG_NAME_CLIENT "--client"
27
- #define ARG_NAME_DEV "--dev"
28
- #define ARG_NAME_SAMPLE "--sample"
29
- #define ARG_NAME_MANAGE "--manage"
30
- #define ARG_NAME_HEADLESS "--headless"
31
- #define ARG_NAME_NG_SERVER "--ng-server"
32
- #define ARG_NAME_NG "--ng"
33
-
34
- #endif /* _ARGNAMES_H */
35
-
1
+ /*
2
+ * Copyright 2009-2010 JRuby Team (www.jruby.org).
3
+ */
4
+
5
+ #ifndef _ARGNAMES_H
6
+ #define _ARGNAMES_H
7
+
8
+ /* Standard Java classpath options */
9
+ #define ARG_NAME_CP "-J-cp"
10
+ #define ARG_NAME_CLASSPATH "-J-classpath"
11
+
12
+ /* These are windows-launcher-specific args. They should be prefixed with -X
13
+ so that they don't clash with normal Ruby args (like --trace for Rake). */
14
+ #define ARG_NAME_SEPAR_PROC "-Xfork-java"
15
+ #define ARG_NAME_CONSOLE "-Xconsole"
16
+ #define ARG_NAME_LAUNCHER_LOG "-Xtrace"
17
+ #define ARG_NAME_BOOTCLASS "-Xbootclass"
18
+ #define ARG_NAME_JDKHOME "-Xjdkhome"
19
+ #define ARG_NAME_CP_PREPEND "-Xcp:p"
20
+ #define ARG_NAME_CP_APPEND "-Xcp:a"
21
+ #define ARG_NAME_CMD_ONLY "-Xcommand"
22
+ #define ARG_NAME_NO_BOOTCLASSPATH "-Xnobootclasspath"
23
+
24
+ /* Below are standard JRuby args handled by the launcher. */
25
+ #define ARG_NAME_SERVER "--server"
26
+ #define ARG_NAME_CLIENT "--client"
27
+ #define ARG_NAME_DEV "--dev"
28
+ #define ARG_NAME_SAMPLE "--sample"
29
+ #define ARG_NAME_MANAGE "--manage"
30
+ #define ARG_NAME_HEADLESS "--headless"
31
+ #define ARG_NAME_NG_SERVER "--ng-server"
32
+ #define ARG_NAME_NG "--ng"
33
+
34
+ #endif /* _ARGNAMES_H */
35
+
@@ -1,667 +1,668 @@
1
- /*
2
- * Copyright 2009-2012 JRuby Team (www.jruby.org).
3
- */
4
-
5
- #include <cstring>
6
- #include <cstdlib>
7
- #include <climits>
8
- #include <memory>
9
- #include <string>
10
- #include <algorithm>
11
- #include <unistd.h>
12
- #include "utilsfuncs.h"
13
- #include "argparser.h"
14
- #include "argnames.h"
15
- #include "version.h"
16
- #include "sys/stat.h"
17
-
18
- #ifndef WIN32
19
- #include <sys/types.h>
20
- #include <sys/utsname.h>
21
- #include <dirent.h>
22
- #define EXEEXT ""
23
- #else
24
- #define EXEEXT ".exe"
25
- #endif
26
-
27
- using namespace std;
28
-
29
- const char *ArgParser::HELP_MSG =
30
- "JRuby Launcher usage: jruby" EXEEXT " {options} arguments\n\n\
31
- To see general JRuby options, type 'jruby -h' or 'jruby --help'.\n\n\
32
- Options:\n\
33
- -Xversion print launcher's version\n\
34
- \nJvm Management:\n\
35
- -Xjdkhome <path> set path to JDK\n\
36
- -J<jvm_option> pass <jvm_option> to JVM\n\
37
- \nClasspath Management:\n\
38
- -Xcp <classpath> set the classpath\n\
39
- -Xcp:p <classpath> prepend <classpath> to classpath\n\
40
- -Xcp:a <classpath> append <classpath> to classpath\n\
41
- -Xnobootclasspath don't put jruby jars on the bootclasspath\n\
42
- \nMisc:\n\
43
- -Xtrace <path> path for launcher log (for troubleshooting)\n\
44
- -Xcommand just print the equivalent java command and exit\n\n\
45
- -Xprop.erty[=value] equivalent to -J-Djruby.<prop.erty>[=value]\n\
46
- -Xproperties list supported properties (omit \"jruby.\" with -X)\n"
47
- #ifdef WIN32
48
- "\
49
- -Xfork-java run java in separate process\n\
50
- -Xconsole <mode> jrubyw console attach mode (new|attach|suppress)\n"
51
- #endif
52
- "\n"
53
- ;
54
-
55
- const char *ArgParser::REQ_JAVA_VERSION = "1.5";
56
-
57
- const char *ArgParser::OPT_JDK_HOME = "-Djdk.home=";
58
- const char *ArgParser::OPT_JRUBY_HOME = "-Djruby.home=";
59
- const char *ArgParser::OPT_JRUBY_COMMAND_NAME = "-Dsun.java.command=";
60
-
61
- const char *ArgParser::OPT_CMDLINE_CLASS_PATH = "-cp";
62
- const char *ArgParser::OPT_CLASS_PATH = "-Djava.class.path=";
63
- const char *ArgParser::OPT_BOOT_CLASS_PATH = "-Xbootclasspath/a:";
64
-
65
- const char *ArgParser::OPT_JFFI_PATH = "-Djffi.boot.library.path=";
66
- const char *ArgParser::OPT_JRUBY_SHELL = "-Djruby.shell=";
67
- const char *ArgParser::OPT_JRUBY_SCRIPT = "-Djruby.script=";
68
- const char *ArgParser::MAIN_CLASS = "org/jruby/Main";
69
- const char *ArgParser::DEFAULT_EXECUTABLE = "jruby";
70
-
71
- ArgParser::ArgParser()
72
- : separateProcess(true)
73
- , nailgunClient(false)
74
- , noBootClassPath(false)
75
- , printCommandLine(false)
76
- {
77
- }
78
-
79
- ArgParser::ArgParser(const ArgParser& orig) {
80
- }
81
-
82
- ArgParser::~ArgParser() {
83
- }
84
-
85
- void ArgParser::addEnvVarToOptions(std::list<std::string> & optionsList, const char * envvar) {
86
- const char * value = getenv(envvar);
87
- string opts("");
88
- if (value) {
89
- opts = value;
90
- }
91
-
92
- if (opts.size() > 0) {
93
- if (opts[0] == '"' || opts[0] == '\'') {
94
- char quote = opts[0];
95
- if (opts[opts.size() - 1] == quote) {
96
- opts = opts.substr(1, opts.size() - 2);
97
- }
98
- }
99
-
100
- size_t start = 0, pos = 0;
101
- while ((pos = opts.find(' ', start)) != string::npos) {
102
- string part(opts.substr(start, pos - start));
103
- if (part.size() > 0) {
104
- logMsg("%s += %s", envvar, part.c_str());
105
- optionsList.push_back(part);
106
- }
107
- start = pos + 1;
108
- }
109
- if (start < opts.size()) {
110
- string part(opts.substr(start));
111
- if (part.size() > 0) {
112
- logMsg("%s += %s", envvar, part.c_str());
113
- optionsList.push_back(part);
114
- }
115
- }
116
- }
117
- }
118
-
119
- #ifdef __MACH__
120
- #include <mach-o/dyld.h>
121
- #endif
122
-
123
- #ifndef PATH_MAX
124
- #define PATH_MAX MAX_PATH
125
- #endif
126
-
127
- bool ArgParser::initPlatformDir() {
128
- bool found = false;
129
- char path[PATH_MAX] = "";
130
-
131
- logMsg("Version: " JRUBY_LAUNCHER_VERSION);
132
-
133
- if (getenv("JRUBY_HOME") != NULL) {
134
- logMsg("initPlatformDir: using JRUBY_HOME environment variable");
135
- char sep[2] = { FILE_SEP, NULL };
136
- strncpy(path, getenv("JRUBY_HOME"), PATH_MAX - 11);
137
- strncpy(path + strlen(path), sep, 1);
138
- strncpy(path + strlen(path), "bin", 3);
139
- strncpy(path + strlen(path), sep, 1);
140
- strncpy(path + strlen(path), "jruby", 5);
141
- found = true;
142
- }
143
-
144
- #ifdef WIN32
145
-
146
- if (!found) {
147
- getCurrentModulePath(path, PATH_MAX);
148
- }
149
-
150
- #else // !WIN32
151
-
152
- if (!found) {
153
- // first try via linux /proc/self/exe
154
- logMsg("initPlatformDir: trying /proc/self/exe");
155
- found = readlink("/proc/self/exe", path, PATH_MAX) != -1;
156
- }
157
-
158
- #ifdef __MACH__
159
- uint32_t sz = PATH_MAX;
160
- if (!found && _NSGetExecutablePath(path, &sz) == 0) { // OSX-specific
161
- logMsg("initPlatformDir: using _NSGetExecutablePath");
162
- string tmpPath(path);
163
- realpath(tmpPath.c_str(), path);
164
- found = true;
165
- }
166
- #endif
167
-
168
- #ifdef __SUNOS__
169
- const char* execname = getexecname();
170
- if (!found && execname) {
171
- logMsg("initPlatformDir: using getexecname");
172
- char * dst = path;
173
- if (execname[0] != '/') {
174
- getcwd(path, PATH_MAX - strlen(execname) - 2);
175
- dst = path + strlen(path);
176
- *dst++ = '/';
177
- }
178
-
179
- strncpy(dst, execname, strlen(execname));
180
- found = true;
181
- }
182
- #endif
183
-
184
- if (!found && platformDir[0] == '/') { // argv[0]: absolute path
185
- logMsg("initPlatformDir: argv[0] appears to be an absolute path");
186
- strncpy(path, platformDir.c_str(), PATH_MAX);
187
- found = true;
188
- }
189
-
190
- if (!found && platformDir.find('/') != string::npos) { // argv[0]: relative path
191
- logMsg("initPlatformDir: argv[0] appears to be a relative path");
192
- getcwd(path, PATH_MAX - platformDir.length() - 1);
193
- strncpy(path + strlen(path), platformDir.c_str(), platformDir.length());
194
- found = true;
195
- }
196
- #endif // WIN32
197
-
198
- if (!found) { // try via PATH search
199
- logMsg("initPlatformDir: trying to find executable on PATH");
200
- std::string location = findOnPath(platformDir.c_str());
201
- if (location.size() > 0) {
202
- strncpy(path, location.c_str(), PATH_MAX);
203
- found = true;
204
- }
205
- }
206
-
207
- // Check if bin/jruby file exists; this logs a message if not found
208
- fileExists(path);
209
-
210
- logMsg("Module: %s", path);
211
- char *bslash = strrchr(path, FILE_SEP);
212
- if (!bslash) {
213
- return false;
214
- }
215
- *bslash = '\0';
216
- bslash = strrchr(path, FILE_SEP);
217
- if (!bslash) {
218
- return false;
219
- }
220
- *bslash = '\0';
221
- platformDir = path;
222
- logMsg("Platform dir: %s", platformDir.c_str());
223
- return true;
224
- }
225
-
226
- bool ArgParser::parseArgs(int argc, char *argv[]) {
227
- list<string> args;
228
-
229
- #define CHECK_ARG \
230
- it++; \
231
- if (it == args.end() || it->empty() || it->at(0) == '-') { \
232
- logErr(false, true, "Argument is missing for \"%s\" option.", (--it)->c_str()); \
233
- return false; \
234
- } \
235
- it--;
236
- #define INCR ++it, ++i
237
-
238
- addEnvVarToOptions(javaOptions, "JAVA_OPTS");
239
- addEnvVarToOptions(args, "JRUBY_OPTS");
240
-
241
- #ifdef __MACH__
242
- if (getenv("JAVA_ENCODING") == NULL) {
243
- javaOptions.push_back("-Dfile.encoding=UTF-8");
244
- }
245
- #endif
246
- if (getenv("VERIFY_JRUBY") != NULL) {
247
- noBootClassPath = true;
248
- }
249
-
250
- const char *java_mem = getenv("JAVA_MEM");
251
- if (java_mem != NULL) {
252
- javaOptions.push_back(java_mem);
253
- }
254
-
255
- const char *java_stack = getenv("JAVA_STACK");
256
- if (java_stack != NULL) {
257
- javaOptions.push_back(java_stack);
258
- }
259
-
260
- addToArgList(args, argc, argv);
261
-
262
- logMsg("Parsing arguments:");
263
- for (list<string>::iterator it = args.begin(); it != args.end(); ++it) {
264
- logMsg("\t%s", it->c_str());
265
- }
266
-
267
- bool doneScanning = false;
268
-
269
- int i = 0;
270
- for (list<string>::iterator it = args.begin(); it != args.end(); INCR) {
271
- if (doneScanning) {
272
- progArgs.push_back(*it);
273
- } else if (it->compare("--") == 0 || it->empty() || it->at(0) != '-') {
274
- progArgs.push_back(*it);
275
- doneScanning = true;
276
- } else if (it->compare(ARG_NAME_SEPAR_PROC) == 0) {
277
- separateProcess = true;
278
- logMsg("Run Java in separater process");
279
- } else if (it->compare(ARG_NAME_CMD_ONLY) == 0) {
280
- printCommandLine = true;
281
- } else if (it->compare(ARG_NAME_NO_BOOTCLASSPATH) == 0) {
282
- noBootClassPath = true;
283
- } else if (it->compare(ARG_NAME_LAUNCHER_LOG) == 0) {
284
- // We only check the validity of args here,
285
- // the actual parsing and setting the log file
286
- // is done earlier, in checkLoggingArg()
287
- CHECK_ARG;
288
- INCR;
289
- } else if (it->compare(ARG_NAME_BOOTCLASS) == 0) {
290
- CHECK_ARG;
291
- INCR;
292
- bootclass = *it;
293
- } else if (it->compare(ARG_NAME_JDKHOME) == 0) {
294
- CHECK_ARG;
295
- INCR;
296
- jdkhome = *it;
297
- } else if (it->compare(ARG_NAME_CP_PREPEND) == 0) {
298
- CHECK_ARG;
299
- if (!cpBefore.empty()) {
300
- cpBefore += PATH_SEP;
301
- }
302
- INCR;
303
- cpBefore += *it;
304
- } else if (it->compare(ARG_NAME_CP_APPEND) == 0) {
305
- CHECK_ARG;
306
- if (!cpAfter.empty()) {
307
- cpAfter += PATH_SEP;
308
- }
309
- INCR;
310
- cpAfter += *it;
311
- } else if (it->compare(ARG_NAME_CP) == 0
312
- || it->compare(ARG_NAME_CLASSPATH) == 0) {
313
- CHECK_ARG;
314
- if (!cpExplicit.empty()) {
315
- cpExplicit += PATH_SEP;
316
- }
317
- INCR;
318
- cpExplicit += *it;
319
- } else if (it->compare(ARG_NAME_SERVER) == 0
320
- || it->compare(ARG_NAME_CLIENT) == 0) {
321
- javaOptions.push_back(it->substr(1)); // to JVMLauncher, -server instead of --server
322
- } else if (it->compare(ARG_NAME_DEV) == 0) {
323
- javaOptions.push_back("-XX:+TieredCompilation");
324
- javaOptions.push_back("-XX:TieredStopAtLevel=1");
325
- javaOptions.push_back("-Djruby.compile.mode=OFF");
326
- javaOptions.push_back("-Djruby.compile.invokedynamic=false");
327
- progArgs.push_back(*it); // allow JRuby to process it too
328
- } else if (it->compare(ARG_NAME_SAMPLE) == 0) {
329
- javaOptions.push_back("-Xprof");
330
- } else if (it->compare(ARG_NAME_MANAGE) == 0) {
331
- javaOptions.push_back("-Dcom.sun.management.jmxremote");
332
- javaOptions.push_back("-Djruby.management.enabled=true");
333
- } else if (it->compare(ARG_NAME_HEADLESS) == 0) {
334
- javaOptions.push_back("-Djava.awt.headless=true");
335
- } else if (it->compare(ARG_NAME_NG) == 0) {
336
- nailgunClient = true;
337
- } else if (it->compare(ARG_NAME_NG_SERVER) == 0) {
338
- bootclass = "com/martiansoftware/nailgun/NGServer";
339
- javaOptions.push_back("-server");
340
- noBootClassPath = true;
341
- } else if (it->compare(0, 2, "-J", 2) == 0) {
342
- std::string javaOpt = it->substr(2);
343
- if (javaOpt.compare(0, 3, "-ea", 3) == 0
344
- || javaOpt.compare(0, 17, "-enableassertions", 17) == 0) {
345
- logMsg("Note: -ea option is specified, there will be no bootclasspath in order to enable assertions");
346
- noBootClassPath = true;
347
- }
348
- javaOptions.push_back(javaOpt);
349
- } else if (strcmp(it->c_str(), "-Xhelp") == 0 || strcmp(it->c_str(), "-X") == 0) {
350
- printToConsole(HELP_MSG);
351
- if (!appendHelp.empty()) {
352
- printToConsole(appendHelp.c_str());
353
- }
354
- javaOptions.push_back("-Djruby.launcher.nopreamble=true");
355
- progArgs.push_back("-X");
356
- } else if (strcmp(it->c_str(), "-Xversion") == 0) {
357
- printToConsole("JRuby Launcher Version " JRUBY_LAUNCHER_VERSION "\n");
358
- return false;
359
- } else if (strcmp(it->c_str(), "-Xversion") == 0) {
360
- printToConsole("JRuby Launcher Version " JRUBY_LAUNCHER_VERSION "\n");
361
- return false;
362
- } else if (strcmp(it->c_str(), "-Xproperties") == 0) {
363
- progArgs.push_back(std::string("--properties"));
364
- } else if (endsWith(*it, "?") || endsWith(*it, "...")) {
365
- progArgs.push_back(*it);
366
- } else if (it->compare(0, 2, "-X", 2) == 0 && islower(it->c_str()[2])) {
367
- // Any other /-X([a-z].*)/ get turned into a -Djruby.\1 property
368
- std::string propPart = it->substr(2);
369
- std::string propSet = std::string("-Djruby.");
370
- propSet += propPart;
371
- javaOptions.push_back(propSet);
372
- } else {
373
- progArgs.push_back(*it);
374
- }
375
- }
376
-
377
- return true;
378
- }
379
-
380
- void ArgParser::prepareOptions() {
381
- list<string> userOptions(javaOptions);
382
- javaOptions.clear();
383
-
384
- string option = OPT_JDK_HOME;
385
- option += jdkhome;
386
- javaOptions.push_back(option);
387
-
388
- option = OPT_JRUBY_HOME;
389
- option += platformDir;
390
- javaOptions.push_back(option);
391
-
392
- option = OPT_JRUBY_SCRIPT;
393
- option += "jruby";
394
- javaOptions.push_back(option);
395
-
396
- option = OPT_JRUBY_SHELL;
397
- #ifdef WIN32
398
- option += "cmd.exe";
399
- #else
400
- option += "/bin/sh";
401
- #endif
402
- javaOptions.push_back(option);
403
-
404
- option = OPT_JFFI_PATH;
405
-
406
- string jniDir;
407
- #ifdef WIN32
408
- string newJniDir = platformDir + "\\lib\\jni";
409
- string oldJniDir = platformDir + "\\lib\\native";
410
- #else
411
- string newJniDir = platformDir + "/lib/jni";
412
- string oldJniDir = platformDir + "/lib/native";
413
- #endif
414
-
415
- struct stat jniDirStat;
416
- if (stat(newJniDir.c_str(), &jniDirStat) == 0) {
417
- jniDir = newJniDir;
418
- } else {
419
- jniDir = oldJniDir;
420
- }
421
-
422
- #ifdef WIN32
423
- option += (jniDir + ";"
424
- + jniDir + "\\i386-Windows;"
425
- + jniDir + "\\x86_64-Windows");
426
- #else
427
- struct utsname name;
428
- if (uname(&name) == 0) {
429
- string ffiBase(jniDir);
430
- string ffiPath = ffiBase;
431
- DIR* dir = opendir(ffiBase.c_str());
432
- struct dirent* ent;
433
- if (dir != NULL) {
434
- while ((ent = readdir(dir)) != NULL) {
435
- string entry(ent->d_name);
436
- if (entry.find(name.sysname) != string::npos) {
437
- if (!ffiPath.empty()) {
438
- ffiPath += PATH_SEP;
439
- }
440
- ffiPath += ffiBase + FILE_SEP + entry;
441
- }
442
- }
443
- closedir(dir);
444
- }
445
- option += ffiPath;
446
- }
447
- #endif
448
- javaOptions.push_back(option);
449
-
450
- setupMaxHeapAndStack(userOptions);
451
-
452
- constructBootClassPath();
453
- constructClassPath();
454
-
455
- if (bootclass.empty()) {
456
- bootclass = MAIN_CLASS;
457
- }
458
-
459
- // replace '/' by '.' to report a better name to jps/jconsole
460
- string cmdName = bootclass;
461
- size_t position = cmdName.find("/");
462
- while (position != string::npos) {
463
- cmdName.replace(position, 1, ".");
464
- position = cmdName.find("/", position + 1);
465
- }
466
-
467
- option = OPT_JRUBY_COMMAND_NAME;
468
- option += cmdName;
469
- javaOptions.push_back(option);
470
-
471
- // When launching a separate process, use '-cp' which expands embedded wildcards
472
- if (separateProcess) {
473
- javaOptions.push_back(OPT_CMDLINE_CLASS_PATH);
474
- javaOptions.push_back(classPath);
475
- } else {
476
- option = OPT_CLASS_PATH;
477
- option += classPath;
478
- javaOptions.push_back(option);
479
- }
480
-
481
- if (!bootClassPath.empty()) {
482
- option = OPT_BOOT_CLASS_PATH;
483
- option += bootClassPath;
484
- javaOptions.push_back(option);
485
- }
486
-
487
- javaOptions.insert(javaOptions.end(), userOptions.begin(), userOptions.end());
488
- }
489
-
490
- void ArgParser::setupMaxHeapAndStack(list<string> userOptions) {
491
- // Hard-coded 500m, 2048k is for consistency with jruby shell script.
492
- string heapSize("500m"), stackSize("2048k");
493
- bool maxHeap = false, maxStack = false;
494
- for (list<string>::iterator it = userOptions.begin(); it != userOptions.end(); it++) {
495
- if (!maxHeap && strncmp("-Xmx", it->c_str(), 4) == 0) {
496
- heapSize = it->substr(4, it->size() - 4);
497
- maxHeap = true;
498
- }
499
- if (!maxStack && strncmp("-Xss", it->c_str(), 4) == 0) {
500
- stackSize = it->substr(4, it->size() - 4);
501
- maxStack = true;
502
- }
503
- }
504
- if (!maxHeap) {
505
- javaOptions.push_back("-Xmx" + heapSize);
506
- }
507
- if (!maxStack) {
508
- javaOptions.push_back("-Xss" + stackSize);
509
- }
510
- }
511
-
512
- void ArgParser::constructBootClassPath() {
513
- logMsg("constructBootClassPath()");
514
- addedToBootCP.clear();
515
- addedToCP.clear();
516
- classPath = cpBefore;
517
-
518
- string jruby_complete_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby-complete.jar";
519
- string jruby_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby.jar";
520
-
521
- if (fileExists(jruby_jar.c_str())) {
522
- addToBootClassPath(jruby_jar.c_str(), true);
523
- if (fileExists(jruby_complete_jar.c_str())) {
524
- printToConsole("WARNING: Both jruby-complete.jar and jruby.jar are present in the 'lib' directory. Will use jruby.jar\n");
525
- }
526
- } else if (fileExists(jruby_complete_jar.c_str())) {
527
- addToBootClassPath(jruby_complete_jar.c_str());
528
- }
529
-
530
- #ifdef DISTRO_BOOT_CLASS_PATH
531
- // hack converting macro to string
532
- #define STR_HACK2(x) #x
533
- #define STR_HACK(x) STR_HACK2(x)
534
- addToBootClassPath(STR_HACK(DISTRO_BOOT_CLASS_PATH));
535
- #endif
536
-
537
-
538
- logMsg("BootclassPath: %s", bootClassPath.c_str());
539
- }
540
-
541
- void ArgParser::constructClassPath() {
542
- logMsg("constructClassPath()");
543
-
544
- addJarsToClassPathFrom(platformDir.c_str());
545
-
546
- if (cpExplicit.empty()) {
547
- logMsg("No explicit classpath option is used, looking up %%CLASSPATH%% env");
548
- char *envCP = getenv("CLASSPATH");
549
- if (envCP) {
550
- addToClassPath(envCP, false);
551
- }
552
- } else {
553
- logMsg("Explicit classpath option is used, ignoring %%CLASSPATH%% env");
554
- addToClassPath(cpExplicit.c_str(), false);
555
- }
556
-
557
- if (!cpAfter.empty()) {
558
- classPath += PATH_SEP;
559
- classPath += cpAfter;
560
- }
561
-
562
- // JRUBY-4709: Include this by default to have PWD as part of classpath
563
- if (!classPath.empty()) {
564
- classPath += PATH_SEP;
565
- }
566
-
567
- logMsg("ClassPath: %s", classPath.c_str());
568
- }
569
-
570
- void ArgParser::addJarsToClassPathFrom(const char *dir) {
571
- logMsg("addJarsToClassPathFrom()\n\tdir: %s", dir);
572
- string path = dir;
573
- path += FILE_SEP;
574
- path += "lib";
575
-
576
- #ifdef WIN32
577
- WIN32_FIND_DATA fd = {0};
578
- string patternPath = path + FILE_SEP + "*.jar";
579
- HANDLE hFind = FindFirstFile(patternPath.c_str(), &fd);
580
- if (hFind == INVALID_HANDLE_VALUE) {
581
- logMsg("Nothing found (%s)", patternPath.c_str());
582
- return;
583
- }
584
- do {
585
- string fullName = path + FILE_SEP + fd.cFileName;
586
- addToClassPath(fullName.c_str());
587
- } while (FindNextFile(hFind, &fd));
588
- FindClose(hFind);
589
- #else
590
- DIR *directory = opendir(path.c_str());
591
- if (!directory) {
592
- logMsg("Nothing found (%s)", path.c_str());
593
- return;
594
- }
595
-
596
- struct dirent *ent;
597
- while((ent = readdir(directory)) != NULL) {
598
- int len = strlen(ent->d_name);
599
- if (len > 4 && strncmp(".jar", (ent->d_name + (len - 4)), 4) == 0) {
600
- string fullName = path + FILE_SEP + ent->d_name;
601
- addToClassPath(fullName.c_str());
602
- }
603
- }
604
- closedir(directory);
605
- #endif
606
- }
607
-
608
- void ArgParser::addToClassPath(const char *path, bool onlyIfExists) {
609
- logMsg("addToClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
610
- if (onlyIfExists && !fileExists(path)) {
611
- return;
612
- }
613
-
614
- if (!addedToCP.insert(path).second) {
615
- logMsg("\"%s\" already added, skipping", path);
616
- return;
617
- }
618
-
619
- // check that this hasn't been added to boot class path already
620
- if (addedToBootCP.find(path) == addedToBootCP.end()) {
621
- if (!classPath.empty()) {
622
- classPath += PATH_SEP;
623
- }
624
- classPath += path;
625
- } else {
626
- logMsg("No need to add \"%s\" to classpath, it's already in bootclasspath", path);
627
- }
628
- }
629
-
630
- void ArgParser::addToBootClassPath(const char *path, bool onlyIfExists) {
631
- logMsg("addToBootClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
632
-
633
- if (noBootClassPath) {
634
- logMsg("NOTE: In this mode there is no bootclasspath, adding to the classpath instead...");
635
- return addToClassPath(path, onlyIfExists);
636
- }
637
-
638
- if (onlyIfExists && !fileExists(path)) {
639
- return;
640
- }
641
-
642
- // only add non-duplicates
643
- if (addedToBootCP.insert(path).second) {
644
- if (!bootClassPath.empty()) {
645
- bootClassPath += PATH_SEP;
646
- }
647
- bootClassPath += path;
648
- } else {
649
- logMsg("\"%s\" already in bootclasspath", path);
650
- }
651
- }
652
-
653
- void ArgParser::appendToHelp(const char *msg) {
654
- if (msg) {
655
- appendHelp = msg;
656
- }
657
- }
658
-
659
- void ArgParser::addOptionsToCommandLine(list<string> & commandLine) {
660
- commandLine.insert(commandLine.end(), javaOptions.begin(), javaOptions.end());
661
- commandLine.insert(commandLine.end(), bootclass);
662
- commandLine.insert(commandLine.end(), progArgs.begin(), progArgs.end());
663
- }
664
-
665
- bool ArgParser::endsWith(const std::string &string, const std::string &end) {
666
- return std::equal(string.begin() + string.size() - end.size(), string.end(), end.begin());
667
- }
1
+ /*
2
+ * Copyright 2009-2012 JRuby Team (www.jruby.org).
3
+ */
4
+
5
+ #include <cstring>
6
+ #include <cstdlib>
7
+ #include <climits>
8
+ #include <memory>
9
+ #include <string>
10
+ #include <algorithm>
11
+ #include <unistd.h>
12
+ #include <limits>
13
+ #include "utilsfuncs.h"
14
+ #include "argparser.h"
15
+ #include "argnames.h"
16
+ #include "version.h"
17
+ #include "sys/stat.h"
18
+
19
+ #ifndef WIN32
20
+ #include <sys/types.h>
21
+ #include <sys/utsname.h>
22
+ #include <dirent.h>
23
+ #define EXEEXT ""
24
+ #else
25
+ #define EXEEXT ".exe"
26
+ #endif
27
+
28
+ using namespace std;
29
+
30
+ const char *ArgParser::HELP_MSG =
31
+ "JRuby Launcher usage: jruby" EXEEXT " {options} arguments\n\n\
32
+ To see general JRuby options, type 'jruby -h' or 'jruby --help'.\n\n\
33
+ Options:\n\
34
+ -Xversion print launcher's version\n\
35
+ \nJvm Management:\n\
36
+ -Xjdkhome <path> set path to JDK\n\
37
+ -J<jvm_option> pass <jvm_option> to JVM\n\
38
+ \nClasspath Management:\n\
39
+ -Xcp <classpath> set the classpath\n\
40
+ -Xcp:p <classpath> prepend <classpath> to classpath\n\
41
+ -Xcp:a <classpath> append <classpath> to classpath\n\
42
+ -Xnobootclasspath don't put jruby jars on the bootclasspath\n\
43
+ \nMisc:\n\
44
+ -Xtrace <path> path for launcher log (for troubleshooting)\n\
45
+ -Xcommand just print the equivalent java command and exit\n\n\
46
+ -Xprop.erty[=value] equivalent to -J-Djruby.<prop.erty>[=value]\n\
47
+ -Xproperties list supported properties (omit \"jruby.\" with -X)\n"
48
+ #ifdef WIN32
49
+ "\
50
+ -Xfork-java run java in separate process\n\
51
+ -Xconsole <mode> jrubyw console attach mode (new|attach|suppress)\n"
52
+ #endif
53
+ "\n"
54
+ ;
55
+
56
+ const char *ArgParser::REQ_JAVA_VERSION = "1.5";
57
+
58
+ const char *ArgParser::OPT_JDK_HOME = "-Djdk.home=";
59
+ const char *ArgParser::OPT_JRUBY_HOME = "-Djruby.home=";
60
+ const char *ArgParser::OPT_JRUBY_COMMAND_NAME = "-Dsun.java.command=";
61
+
62
+ const char *ArgParser::OPT_CMDLINE_CLASS_PATH = "-cp";
63
+ const char *ArgParser::OPT_CLASS_PATH = "-Djava.class.path=";
64
+ const char *ArgParser::OPT_BOOT_CLASS_PATH = "-Xbootclasspath/a:";
65
+
66
+ const char *ArgParser::OPT_JFFI_PATH = "-Djffi.boot.library.path=";
67
+ const char *ArgParser::OPT_JRUBY_SHELL = "-Djruby.shell=";
68
+ const char *ArgParser::OPT_JRUBY_SCRIPT = "-Djruby.script=";
69
+ const char *ArgParser::MAIN_CLASS = "org/jruby/Main";
70
+ const char *ArgParser::DEFAULT_EXECUTABLE = "jruby";
71
+
72
+ ArgParser::ArgParser()
73
+ : separateProcess(true)
74
+ , nailgunClient(false)
75
+ , noBootClassPath(false)
76
+ , printCommandLine(false)
77
+ {
78
+ }
79
+
80
+ ArgParser::ArgParser(const ArgParser& orig) {
81
+ }
82
+
83
+ ArgParser::~ArgParser() {
84
+ }
85
+
86
+ void ArgParser::addEnvVarToOptions(std::list<std::string> & optionsList, const char * envvar) {
87
+ const char * value = getenv(envvar);
88
+ string opts("");
89
+ if (value) {
90
+ opts = value;
91
+ }
92
+
93
+ if (opts.size() > 0) {
94
+ if (opts[0] == '"' || opts[0] == '\'') {
95
+ char quote = opts[0];
96
+ if (opts[opts.size() - 1] == quote) {
97
+ opts = opts.substr(1, opts.size() - 2);
98
+ }
99
+ }
100
+
101
+ size_t start = 0, pos = 0;
102
+ while ((pos = opts.find(' ', start)) != string::npos) {
103
+ string part(opts.substr(start, pos - start));
104
+ if (part.size() > 0) {
105
+ logMsg("%s += %s", envvar, part.c_str());
106
+ optionsList.push_back(part);
107
+ }
108
+ start = pos + 1;
109
+ }
110
+ if (start < opts.size()) {
111
+ string part(opts.substr(start));
112
+ if (part.size() > 0) {
113
+ logMsg("%s += %s", envvar, part.c_str());
114
+ optionsList.push_back(part);
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ #ifdef __MACH__
121
+ #include <mach-o/dyld.h>
122
+ #endif
123
+
124
+ #ifndef PATH_MAX
125
+ #define PATH_MAX MAX_PATH
126
+ #endif
127
+
128
+ bool ArgParser::initPlatformDir() {
129
+ bool found = false;
130
+ char path[PATH_MAX] = "";
131
+
132
+ logMsg("Version: " JRUBY_LAUNCHER_VERSION);
133
+
134
+ if (getenv("JRUBY_HOME") != NULL) {
135
+ logMsg("initPlatformDir: using JRUBY_HOME environment variable");
136
+ char sep[2] = { FILE_SEP, NULL };
137
+ strncpy(path, getenv("JRUBY_HOME"), PATH_MAX - 11);
138
+ strncpy(path + strlen(path), sep, 1);
139
+ strncpy(path + strlen(path), "bin", 3);
140
+ strncpy(path + strlen(path), sep, 1);
141
+ strncpy(path + strlen(path), "jruby", 5);
142
+ found = true;
143
+ }
144
+
145
+ #ifdef WIN32
146
+
147
+ if (!found) {
148
+ getCurrentModulePath(path, PATH_MAX);
149
+ }
150
+
151
+ #else // !WIN32
152
+
153
+ if (!found) {
154
+ // first try via linux /proc/self/exe
155
+ logMsg("initPlatformDir: trying /proc/self/exe");
156
+ found = readlink("/proc/self/exe", path, PATH_MAX) != -1;
157
+ }
158
+
159
+ #ifdef __MACH__
160
+ uint32_t sz = PATH_MAX;
161
+ if (!found && _NSGetExecutablePath(path, &sz) == 0) { // OSX-specific
162
+ logMsg("initPlatformDir: using _NSGetExecutablePath");
163
+ string tmpPath(path);
164
+ realpath(tmpPath.c_str(), path);
165
+ found = true;
166
+ }
167
+ #endif
168
+
169
+ #ifdef __SUNOS__
170
+ const char* execname = getexecname();
171
+ if (!found && execname) {
172
+ logMsg("initPlatformDir: using getexecname");
173
+ char * dst = path;
174
+ if (execname[0] != '/') {
175
+ getcwd(path, PATH_MAX - strlen(execname) - 2);
176
+ dst = path + strlen(path);
177
+ *dst++ = '/';
178
+ }
179
+
180
+ strncpy(dst, execname, strlen(execname));
181
+ found = true;
182
+ }
183
+ #endif
184
+
185
+ if (!found && platformDir[0] == '/') { // argv[0]: absolute path
186
+ logMsg("initPlatformDir: argv[0] appears to be an absolute path");
187
+ strncpy(path, platformDir.c_str(), PATH_MAX);
188
+ found = true;
189
+ }
190
+
191
+ if (!found && platformDir.find('/') != string::npos) { // argv[0]: relative path
192
+ logMsg("initPlatformDir: argv[0] appears to be a relative path");
193
+ getcwd(path, PATH_MAX - platformDir.length() - 1);
194
+ strncpy(path + strlen(path), platformDir.c_str(), platformDir.length());
195
+ found = true;
196
+ }
197
+ #endif // WIN32
198
+
199
+ if (!found) { // try via PATH search
200
+ logMsg("initPlatformDir: trying to find executable on PATH");
201
+ std::string location = findOnPath(platformDir.c_str());
202
+ if (location.size() > 0) {
203
+ strncpy(path, location.c_str(), PATH_MAX);
204
+ found = true;
205
+ }
206
+ }
207
+
208
+ // Check if bin/jruby file exists; this logs a message if not found
209
+ fileExists(path);
210
+
211
+ logMsg("Module: %s", path);
212
+ char *bslash = strrchr(path, FILE_SEP);
213
+ if (!bslash) {
214
+ return false;
215
+ }
216
+ *bslash = '\0';
217
+ bslash = strrchr(path, FILE_SEP);
218
+ if (!bslash) {
219
+ return false;
220
+ }
221
+ *bslash = '\0';
222
+ platformDir = path;
223
+ logMsg("Platform dir: %s", platformDir.c_str());
224
+ return true;
225
+ }
226
+
227
+ bool ArgParser::parseArgs(int argc, char *argv[]) {
228
+ list<string> args;
229
+
230
+ #define CHECK_ARG \
231
+ it++; \
232
+ if (it == args.end() || it->empty() || it->at(0) == '-') { \
233
+ logErr(false, true, "Argument is missing for \"%s\" option.", (--it)->c_str()); \
234
+ return false; \
235
+ } \
236
+ it--;
237
+ #define INCR ++it, ++i
238
+
239
+ addEnvVarToOptions(javaOptions, "JAVA_OPTS");
240
+ addEnvVarToOptions(args, "JRUBY_OPTS");
241
+
242
+ #ifdef __MACH__
243
+ if (getenv("JAVA_ENCODING") == NULL) {
244
+ javaOptions.push_back("-Dfile.encoding=UTF-8");
245
+ }
246
+ #endif
247
+ if (getenv("VERIFY_JRUBY") != NULL) {
248
+ noBootClassPath = true;
249
+ }
250
+
251
+ const char *java_mem = getenv("JAVA_MEM");
252
+ if (java_mem != NULL) {
253
+ javaOptions.push_back(java_mem);
254
+ }
255
+
256
+ const char *java_stack = getenv("JAVA_STACK");
257
+ if (java_stack != NULL) {
258
+ javaOptions.push_back(java_stack);
259
+ }
260
+
261
+ addToArgList(args, argc, argv);
262
+
263
+ logMsg("Parsing arguments:");
264
+ for (list<string>::iterator it = args.begin(); it != args.end(); ++it) {
265
+ logMsg("\t%s", it->c_str());
266
+ }
267
+
268
+ bool doneScanning = false;
269
+
270
+ int i = 0;
271
+ for (list<string>::iterator it = args.begin(); it != args.end(); INCR) {
272
+ if (doneScanning) {
273
+ progArgs.push_back(*it);
274
+ } else if (it->compare("--") == 0 || it->empty() || it->at(0) != '-') {
275
+ progArgs.push_back(*it);
276
+ doneScanning = true;
277
+ } else if (it->compare(ARG_NAME_SEPAR_PROC) == 0) {
278
+ separateProcess = true;
279
+ logMsg("Run Java in separater process");
280
+ } else if (it->compare(ARG_NAME_CMD_ONLY) == 0) {
281
+ printCommandLine = true;
282
+ } else if (it->compare(ARG_NAME_NO_BOOTCLASSPATH) == 0) {
283
+ noBootClassPath = true;
284
+ } else if (it->compare(ARG_NAME_LAUNCHER_LOG) == 0) {
285
+ // We only check the validity of args here,
286
+ // the actual parsing and setting the log file
287
+ // is done earlier, in checkLoggingArg()
288
+ CHECK_ARG;
289
+ INCR;
290
+ } else if (it->compare(ARG_NAME_BOOTCLASS) == 0) {
291
+ CHECK_ARG;
292
+ INCR;
293
+ bootclass = *it;
294
+ } else if (it->compare(ARG_NAME_JDKHOME) == 0) {
295
+ CHECK_ARG;
296
+ INCR;
297
+ jdkhome = *it;
298
+ } else if (it->compare(ARG_NAME_CP_PREPEND) == 0) {
299
+ CHECK_ARG;
300
+ if (!cpBefore.empty()) {
301
+ cpBefore += PATH_SEP;
302
+ }
303
+ INCR;
304
+ cpBefore += *it;
305
+ } else if (it->compare(ARG_NAME_CP_APPEND) == 0) {
306
+ CHECK_ARG;
307
+ if (!cpAfter.empty()) {
308
+ cpAfter += PATH_SEP;
309
+ }
310
+ INCR;
311
+ cpAfter += *it;
312
+ } else if (it->compare(ARG_NAME_CP) == 0
313
+ || it->compare(ARG_NAME_CLASSPATH) == 0) {
314
+ CHECK_ARG;
315
+ if (!cpExplicit.empty()) {
316
+ cpExplicit += PATH_SEP;
317
+ }
318
+ INCR;
319
+ cpExplicit += *it;
320
+ } else if (it->compare(ARG_NAME_SERVER) == 0
321
+ || it->compare(ARG_NAME_CLIENT) == 0) {
322
+ javaOptions.push_back(it->substr(1)); // to JVMLauncher, -server instead of --server
323
+ } else if (it->compare(ARG_NAME_DEV) == 0) {
324
+ javaOptions.push_back("-XX:+TieredCompilation");
325
+ javaOptions.push_back("-XX:TieredStopAtLevel=1");
326
+ javaOptions.push_back("-Djruby.compile.mode=OFF");
327
+ javaOptions.push_back("-Djruby.compile.invokedynamic=false");
328
+ progArgs.push_back(*it); // allow JRuby to process it too
329
+ } else if (it->compare(ARG_NAME_SAMPLE) == 0) {
330
+ javaOptions.push_back("-Xprof");
331
+ } else if (it->compare(ARG_NAME_MANAGE) == 0) {
332
+ javaOptions.push_back("-Dcom.sun.management.jmxremote");
333
+ javaOptions.push_back("-Djruby.management.enabled=true");
334
+ } else if (it->compare(ARG_NAME_HEADLESS) == 0) {
335
+ javaOptions.push_back("-Djava.awt.headless=true");
336
+ } else if (it->compare(ARG_NAME_NG) == 0) {
337
+ nailgunClient = true;
338
+ } else if (it->compare(ARG_NAME_NG_SERVER) == 0) {
339
+ bootclass = "com/martiansoftware/nailgun/NGServer";
340
+ javaOptions.push_back("-server");
341
+ noBootClassPath = true;
342
+ } else if (it->compare(0, 2, "-J", 2) == 0) {
343
+ std::string javaOpt = it->substr(2);
344
+ if (javaOpt.compare(0, 3, "-ea", 3) == 0
345
+ || javaOpt.compare(0, 17, "-enableassertions", 17) == 0) {
346
+ logMsg("Note: -ea option is specified, there will be no bootclasspath in order to enable assertions");
347
+ noBootClassPath = true;
348
+ }
349
+ javaOptions.push_back(javaOpt);
350
+ } else if (strcmp(it->c_str(), "-Xhelp") == 0 || strcmp(it->c_str(), "-X") == 0) {
351
+ printToConsole(HELP_MSG);
352
+ if (!appendHelp.empty()) {
353
+ printToConsole(appendHelp.c_str());
354
+ }
355
+ javaOptions.push_back("-Djruby.launcher.nopreamble=true");
356
+ progArgs.push_back("-X");
357
+ } else if (strcmp(it->c_str(), "-Xversion") == 0) {
358
+ printToConsole("JRuby Launcher Version " JRUBY_LAUNCHER_VERSION "\n");
359
+ return false;
360
+ } else if (strcmp(it->c_str(), "-Xversion") == 0) {
361
+ printToConsole("JRuby Launcher Version " JRUBY_LAUNCHER_VERSION "\n");
362
+ return false;
363
+ } else if (strcmp(it->c_str(), "-Xproperties") == 0) {
364
+ progArgs.push_back(std::string("--properties"));
365
+ } else if (endsWith(*it, "?") || endsWith(*it, "...")) {
366
+ progArgs.push_back(*it);
367
+ } else if (it->compare(0, 2, "-X", 2) == 0 && islower(it->c_str()[2])) {
368
+ // Any other /-X([a-z].*)/ get turned into a -Djruby.\1 property
369
+ std::string propPart = it->substr(2);
370
+ std::string propSet = std::string("-Djruby.");
371
+ propSet += propPart;
372
+ javaOptions.push_back(propSet);
373
+ } else {
374
+ progArgs.push_back(*it);
375
+ }
376
+ }
377
+
378
+ return true;
379
+ }
380
+
381
+ void ArgParser::prepareOptions() {
382
+ list<string> userOptions(javaOptions);
383
+ javaOptions.clear();
384
+
385
+ string option = OPT_JDK_HOME;
386
+ option += jdkhome;
387
+ javaOptions.push_back(option);
388
+
389
+ option = OPT_JRUBY_HOME;
390
+ option += platformDir;
391
+ javaOptions.push_back(option);
392
+
393
+ option = OPT_JRUBY_SCRIPT;
394
+ option += "jruby";
395
+ javaOptions.push_back(option);
396
+
397
+ option = OPT_JRUBY_SHELL;
398
+ #ifdef WIN32
399
+ option += "cmd.exe";
400
+ #else
401
+ option += "/bin/sh";
402
+ #endif
403
+ javaOptions.push_back(option);
404
+
405
+ option = OPT_JFFI_PATH;
406
+
407
+ string jniDir;
408
+ #ifdef WIN32
409
+ string newJniDir = platformDir + "\\lib\\jni";
410
+ string oldJniDir = platformDir + "\\lib\\native";
411
+ #else
412
+ string newJniDir = platformDir + "/lib/jni";
413
+ string oldJniDir = platformDir + "/lib/native";
414
+ #endif
415
+
416
+ struct stat jniDirStat;
417
+ if (stat(newJniDir.c_str(), &jniDirStat) == 0) {
418
+ jniDir = newJniDir;
419
+ } else {
420
+ jniDir = oldJniDir;
421
+ }
422
+
423
+ #ifdef WIN32
424
+ option += (jniDir + ";"
425
+ + jniDir + "\\i386-Windows;"
426
+ + jniDir + "\\x86_64-Windows");
427
+ #else
428
+ struct utsname name;
429
+ if (uname(&name) == 0) {
430
+ string ffiBase(jniDir);
431
+ string ffiPath = ffiBase;
432
+ DIR* dir = opendir(ffiBase.c_str());
433
+ struct dirent* ent;
434
+ if (dir != NULL) {
435
+ while ((ent = readdir(dir)) != NULL) {
436
+ string entry(ent->d_name);
437
+ if (entry.find(name.sysname) != string::npos) {
438
+ if (!ffiPath.empty()) {
439
+ ffiPath += PATH_SEP;
440
+ }
441
+ ffiPath += ffiBase + FILE_SEP + entry;
442
+ }
443
+ }
444
+ closedir(dir);
445
+ }
446
+ option += ffiPath;
447
+ }
448
+ #endif
449
+ javaOptions.push_back(option);
450
+
451
+ setupMaxHeapAndStack(userOptions);
452
+
453
+ constructBootClassPath();
454
+ constructClassPath();
455
+
456
+ if (bootclass.empty()) {
457
+ bootclass = MAIN_CLASS;
458
+ }
459
+
460
+ // replace '/' by '.' to report a better name to jps/jconsole
461
+ string cmdName = bootclass;
462
+ size_t position = cmdName.find("/");
463
+ while (position != string::npos) {
464
+ cmdName.replace(position, 1, ".");
465
+ position = cmdName.find("/", position + 1);
466
+ }
467
+
468
+ option = OPT_JRUBY_COMMAND_NAME;
469
+ option += cmdName;
470
+ javaOptions.push_back(option);
471
+
472
+ // When launching a separate process, use '-cp' which expands embedded wildcards
473
+ if (separateProcess) {
474
+ javaOptions.push_back(OPT_CMDLINE_CLASS_PATH);
475
+ javaOptions.push_back(classPath);
476
+ } else {
477
+ option = OPT_CLASS_PATH;
478
+ option += classPath;
479
+ javaOptions.push_back(option);
480
+ }
481
+
482
+ if (!bootClassPath.empty()) {
483
+ option = OPT_BOOT_CLASS_PATH;
484
+ option += bootClassPath;
485
+ javaOptions.push_back(option);
486
+ }
487
+
488
+ javaOptions.insert(javaOptions.end(), userOptions.begin(), userOptions.end());
489
+ }
490
+
491
+ void ArgParser::setupMaxHeapAndStack(list<string> userOptions) {
492
+ // Hard-coded 500m, 2048k is for consistency with jruby shell script.
493
+ string heapSize("500m"), stackSize("2048k");
494
+ bool maxHeap = false, maxStack = false;
495
+ for (list<string>::iterator it = userOptions.begin(); it != userOptions.end(); it++) {
496
+ if (!maxHeap && strncmp("-Xmx", it->c_str(), 4) == 0) {
497
+ heapSize = it->substr(4, it->size() - 4);
498
+ maxHeap = true;
499
+ }
500
+ if (!maxStack && strncmp("-Xss", it->c_str(), 4) == 0) {
501
+ stackSize = it->substr(4, it->size() - 4);
502
+ maxStack = true;
503
+ }
504
+ }
505
+ if (!maxHeap) {
506
+ javaOptions.push_back("-Xmx" + heapSize);
507
+ }
508
+ if (!maxStack) {
509
+ javaOptions.push_back("-Xss" + stackSize);
510
+ }
511
+ }
512
+
513
+ void ArgParser::constructBootClassPath() {
514
+ logMsg("constructBootClassPath()");
515
+ addedToBootCP.clear();
516
+ addedToCP.clear();
517
+ classPath = cpBefore;
518
+
519
+ string jruby_complete_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby-complete.jar";
520
+ string jruby_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby.jar";
521
+
522
+ if (fileExists(jruby_jar.c_str())) {
523
+ addToBootClassPath(jruby_jar.c_str(), true);
524
+ if (fileExists(jruby_complete_jar.c_str())) {
525
+ printToConsole("WARNING: Both jruby-complete.jar and jruby.jar are present in the 'lib' directory. Will use jruby.jar\n");
526
+ }
527
+ } else if (fileExists(jruby_complete_jar.c_str())) {
528
+ addToBootClassPath(jruby_complete_jar.c_str());
529
+ }
530
+
531
+ #ifdef DISTRO_BOOT_CLASS_PATH
532
+ // hack converting macro to string
533
+ #define STR_HACK2(x) #x
534
+ #define STR_HACK(x) STR_HACK2(x)
535
+ addToBootClassPath(STR_HACK(DISTRO_BOOT_CLASS_PATH));
536
+ #endif
537
+
538
+
539
+ logMsg("BootclassPath: %s", bootClassPath.c_str());
540
+ }
541
+
542
+ void ArgParser::constructClassPath() {
543
+ logMsg("constructClassPath()");
544
+
545
+ addJarsToClassPathFrom(platformDir.c_str());
546
+
547
+ if (cpExplicit.empty()) {
548
+ logMsg("No explicit classpath option is used, looking up %%CLASSPATH%% env");
549
+ char *envCP = getenv("CLASSPATH");
550
+ if (envCP) {
551
+ addToClassPath(envCP, false);
552
+ }
553
+ } else {
554
+ logMsg("Explicit classpath option is used, ignoring %%CLASSPATH%% env");
555
+ addToClassPath(cpExplicit.c_str(), false);
556
+ }
557
+
558
+ if (!cpAfter.empty()) {
559
+ classPath += PATH_SEP;
560
+ classPath += cpAfter;
561
+ }
562
+
563
+ // JRUBY-4709: Include this by default to have PWD as part of classpath
564
+ if (!classPath.empty()) {
565
+ classPath += PATH_SEP;
566
+ }
567
+
568
+ logMsg("ClassPath: %s", classPath.c_str());
569
+ }
570
+
571
+ void ArgParser::addJarsToClassPathFrom(const char *dir) {
572
+ logMsg("addJarsToClassPathFrom()\n\tdir: %s", dir);
573
+ string path = dir;
574
+ path += FILE_SEP;
575
+ path += "lib";
576
+
577
+ #ifdef WIN32
578
+ WIN32_FIND_DATA fd = {0};
579
+ string patternPath = path + FILE_SEP + "*.jar";
580
+ HANDLE hFind = FindFirstFile(patternPath.c_str(), &fd);
581
+ if (hFind == INVALID_HANDLE_VALUE) {
582
+ logMsg("Nothing found (%s)", patternPath.c_str());
583
+ return;
584
+ }
585
+ do {
586
+ string fullName = path + FILE_SEP + fd.cFileName;
587
+ addToClassPath(fullName.c_str());
588
+ } while (FindNextFile(hFind, &fd));
589
+ FindClose(hFind);
590
+ #else
591
+ DIR *directory = opendir(path.c_str());
592
+ if (!directory) {
593
+ logMsg("Nothing found (%s)", path.c_str());
594
+ return;
595
+ }
596
+
597
+ struct dirent *ent;
598
+ while((ent = readdir(directory)) != NULL) {
599
+ int len = strlen(ent->d_name);
600
+ if (len > 4 && strncmp(".jar", (ent->d_name + (len - 4)), 4) == 0) {
601
+ string fullName = path + FILE_SEP + ent->d_name;
602
+ addToClassPath(fullName.c_str());
603
+ }
604
+ }
605
+ closedir(directory);
606
+ #endif
607
+ }
608
+
609
+ void ArgParser::addToClassPath(const char *path, bool onlyIfExists) {
610
+ logMsg("addToClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
611
+ if (onlyIfExists && !fileExists(path)) {
612
+ return;
613
+ }
614
+
615
+ if (!addedToCP.insert(path).second) {
616
+ logMsg("\"%s\" already added, skipping", path);
617
+ return;
618
+ }
619
+
620
+ // check that this hasn't been added to boot class path already
621
+ if (addedToBootCP.find(path) == addedToBootCP.end()) {
622
+ if (!classPath.empty()) {
623
+ classPath += PATH_SEP;
624
+ }
625
+ classPath += path;
626
+ } else {
627
+ logMsg("No need to add \"%s\" to classpath, it's already in bootclasspath", path);
628
+ }
629
+ }
630
+
631
+ void ArgParser::addToBootClassPath(const char *path, bool onlyIfExists) {
632
+ logMsg("addToBootClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
633
+
634
+ if (noBootClassPath) {
635
+ logMsg("NOTE: In this mode there is no bootclasspath, adding to the classpath instead...");
636
+ return addToClassPath(path, onlyIfExists);
637
+ }
638
+
639
+ if (onlyIfExists && !fileExists(path)) {
640
+ return;
641
+ }
642
+
643
+ // only add non-duplicates
644
+ if (addedToBootCP.insert(path).second) {
645
+ if (!bootClassPath.empty()) {
646
+ bootClassPath += PATH_SEP;
647
+ }
648
+ bootClassPath += path;
649
+ } else {
650
+ logMsg("\"%s\" already in bootclasspath", path);
651
+ }
652
+ }
653
+
654
+ void ArgParser::appendToHelp(const char *msg) {
655
+ if (msg) {
656
+ appendHelp = msg;
657
+ }
658
+ }
659
+
660
+ void ArgParser::addOptionsToCommandLine(list<string> & commandLine) {
661
+ commandLine.insert(commandLine.end(), javaOptions.begin(), javaOptions.end());
662
+ commandLine.insert(commandLine.end(), bootclass);
663
+ commandLine.insert(commandLine.end(), progArgs.begin(), progArgs.end());
664
+ }
665
+
666
+ bool ArgParser::endsWith(const std::string &string, const std::string &end) {
667
+ return std::equal(string.begin() + string.size() - end.size(), string.end(), end.begin());
668
+ }