jruby-launcher 1.1.1-java → 1.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
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
+ }