jruby-launcher 0.9.9-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/Makefile ADDED
@@ -0,0 +1,106 @@
1
+ # These line gets substituted with the actual Config::CONFIG items location by extconf.rb
2
+ PREFIX = notspecified
3
+ BINDIR = $(PREFIX)/bin
4
+ SITELIBDIR = $(PREFIX)/lib/ruby/site_ruby/1.8
5
+
6
+ ifeq (true,$(shell test -x $(BINDIR)/jruby && echo true))
7
+ RAKE=$(BINDIR)/jruby -S rake
8
+ else
9
+ RAKE=rake
10
+ endif
11
+
12
+ build: .build-post
13
+
14
+ .build-pre:
15
+
16
+ .build-post: .build-impl build-exe test
17
+
18
+ build-exe:
19
+ @if [ "$(findstring mingw, $(CONF))" ]; then \
20
+ ${MAKE} -f ${SUB_CONFMK} SUBPROJECTS=${SUBPROJECTS} jruby.exe jrubyw.exe; \
21
+ if [ -d ../jruby ]; then cp jruby.exe jrubyw.exe jruby.dll ../jruby/bin/; fi; \
22
+ if [ -d D:/work/jruby-dev/jruby ]; then cp jruby.exe jrubyw.exe jruby.dll D:/work/jruby-dev/jruby/bin/; fi; \
23
+ fi
24
+
25
+ jruby.res: resources/jruby.rc
26
+ windres $^ -O coff -o $@
27
+
28
+ jruby.exe: jrubyexe.cpp nbexecloader.h utilsfuncs.cpp utilsfuncswin.cpp jruby.res
29
+ g++ $(CXXFLAGS) $^ -s -o $@ $(LDLIBSOPTIONS)
30
+
31
+ jrubyw.exe: jrubyexe.cpp nbexecloader.h utilsfuncs.cpp utilsfuncswin.cpp jruby.res
32
+ g++ $(CXXFLAGS) -DJRUBYW -mwindows $^ -s -o $@ $(LDLIBSOPTIONS)
33
+
34
+ install:
35
+ @if [ ! -f ./jruby ]; then echo "Please run 'make' first."; exit 1; fi
36
+ @if [ x$(BINDIR) = xnotspecified/bin ]; then echo "Please define where to install by passing PREFIX=<jruby-home>."; exit 1; fi
37
+ @if [ ! -w $(BINDIR) ]; then echo "'$(BINDIR)' does not exist or cannot write to '$(BINDIR)'."; exit 1; fi
38
+ @if [ -f $(BINDIR)/jruby -a ! -w $(BINDIR)/jruby ]; then echo "Cannot write to '$(BINDIR)/jruby'."; exit 1; fi
39
+ cp ./jruby $(BINDIR)/jruby
40
+ @if [ x$(SITELIBDIR) = xnotspecified/lib/ruby/site_ruby/1.8 ]; then echo "Please define where to install by passing PREFIX=<jruby-home>."; exit 1; fi
41
+ @if [ ! -w $(SITELIBDIR) ]; then echo "'$(SITELIBDIR)' does not exist or cannot write to '$(SITELIBDIR)'."; exit 1; fi
42
+ cp ./lib/rubygems/defaults/jruby_native.rb $(SITELIBDIR)/rubygems/defaults
43
+
44
+ test:
45
+ $(RAKE)
46
+
47
+ # Universal binary on OSX
48
+ FAT_ARCHES=i386 ppc x86_64
49
+
50
+ fat: $(FAT_ARCHES)
51
+ lipo -create $(foreach arch,$(FAT_ARCHES),build/unix/Darwin-$(arch)/jruby-launcher) -output jruby
52
+ $(RAKE)
53
+
54
+ $(FAT_ARCHES):
55
+ $(MAKE) -f $(SUB_CONFMK) CND_PLATFORM=Darwin-$@ CFLAGS="-arch $@" build/unix/Darwin-$@/jruby-launcher
56
+
57
+ clean: .clean-post
58
+
59
+ .clean-pre:
60
+ -rm -rf build/*
61
+
62
+ .clean-post: .clean-impl
63
+ rm -f *.exe *.res
64
+
65
+ clobber: .clobber-post
66
+
67
+ .clobber-pre:
68
+
69
+ .clobber-post: .clobber-impl
70
+
71
+ all: .all-post
72
+
73
+ .all-pre:
74
+
75
+ .all-post: .all-impl
76
+
77
+ help: .help-post
78
+
79
+ .help-pre:
80
+
81
+ .help-post: .help-impl
82
+
83
+ # Use the manually-maintained inc/*.mk makefiles.
84
+ # Pass NETBEANS=true on the command-line to use NB's generated
85
+ # nbproject/*.mk
86
+
87
+ ifdef NETBEANS
88
+ SUB_IMPLMK=nbproject/Makefile-impl.mk
89
+ else
90
+ SUB_IMPLMK=inc/Makefile-impl.mk
91
+ SUB_CONFMK=inc/Makefile-rules.mk
92
+ endif
93
+
94
+ # include project implementation makefile
95
+ include $(SUB_IMPLMK)
96
+
97
+ # Pick conf based on OS. for mingw64, must manually override for now.
98
+ ifeq ($(OS),Windows_NT)
99
+ CONF=mingw
100
+ else
101
+ CONF=unix
102
+ endif
103
+
104
+ ifdef NETBEANS
105
+ SUB_CONFMK=nbproject/Makefile-${CONF}.mk
106
+ endif
data/README.txt ADDED
@@ -0,0 +1,61 @@
1
+ JRuby Native Launcher
2
+
3
+ == Motivation
4
+
5
+ Maintaning JRuby.BAT was, well, to put it mildly, unpleasant. We had
6
+ tens of bugs due to BAT limitations, we had weird behaviors depending
7
+ on the version of Windows, we had a bunch of regressions.
8
+
9
+ See http://jira.codehaus.org/browse/JRUBY-4100 for more details.
10
+
11
+ On UNIX platforms, we had problems because a shell-script can't be put
12
+ as a path in the shebang and couldn't take arguments. (#!/usr/bin/env
13
+ jruby -w)
14
+
15
+ We also wanted to DRY up argument handling, even if it meant ditching
16
+ shell script and writing in lowest-common-denominator C++ (!).
17
+
18
+ == Compile
19
+
20
+ On UNIX, you should be able to just type 'make' and a 'jruby' binary
21
+ will be created in the project directory. Copy this to
22
+ $JRUBY_HOME/bin. On Windows, you should also be able to type 'make' if
23
+ you have the MinGW compiler toolkit installed.
24
+
25
+ Or, open the project in Netbeans 6.8 (with C/C++ plugin installed). If
26
+ Netbeans warns that no compilers found, follow the instructions and
27
+ install the required compilers. Currenty, we support MinGW. More info
28
+ here:
29
+
30
+ http://netbeans.org/community/releases/68/cpp-setup-instructions.html
31
+
32
+ Then, just build it, and you're ready to go. jruby.exe, jrubyw.exe and
33
+ jruby.dll will be created, they need to be copied into $JRUBY_HOME/bin
34
+ directory.
35
+
36
+ Both, 32-bit and 64-bit compilers are supported. Great version of
37
+ 64-bit mingw can be found here: http://www.cadforte.com/system64.html
38
+
39
+ To build 64-bit version of the launcher, use the following from the
40
+ command line:
41
+
42
+ make CONF=mingw64
43
+
44
+ == Run
45
+
46
+ The launcher provides a great logger, use it like this:
47
+
48
+ jruby -Xtrace LOG_FILE.log ....
49
+
50
+ == TODO
51
+
52
+ See TODO.txt file for things that need to be done before this launcher
53
+ could replace jruby.bat.
54
+
55
+ == Thanks
56
+
57
+ The original code is by Netbeans project.
58
+
59
+ == License
60
+
61
+ Read the COPYING file.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'spec/rake/spectask'
2
+ require 'rake/gempackagetask'
3
+ require 'date'
4
+
5
+ Spec::Rake::SpecTask.new
6
+
7
+ task :default => :spec
8
+
9
+ load './lib/jruby-launcher.rb'
10
+
11
+ gemspec = Gem::Specification.new do |s|
12
+ s.name = %q{jruby-launcher}
13
+ s.platform = Gem::Platform.new("java")
14
+ s.version = JRubyLauncher::VERSION
15
+ s.authors = ["Nick Sieger", "Vladimir Sizikov"]
16
+ s.date = Date.today.to_s
17
+ s.description = %q{Builds and installs a native launcher for JRuby on your system}
18
+ s.summary = %q{Native launcher for JRuby}
19
+ s.email = ["nick@nicksieger.com", "vsizikov@gmail.com"]
20
+ s.extensions = ["extconf.rb"]
21
+ s.files = FileList["COPYING", "README.txt", "Makefile", "Rakefile", "*.c", "*.cpp", "*.h", "inc/*.*", "**/*.rb", "resources/*.*"]
22
+ s.homepage = %q{http://jruby.org}
23
+ s.rubyforge_project = %q{jruby-extras}
24
+ end
25
+
26
+ Rake::GemPackageTask.new(gemspec) do |pkg|
27
+ end
data/argnames.h ADDED
@@ -0,0 +1,37 @@
1
+ /*
2
+ * File: argnames.h
3
+ * Author: Holy
4
+ *
5
+ * Created on 4. prosinec 2008, 14:13
6
+ */
7
+
8
+ #ifndef _ARGNAMES_H
9
+ #define _ARGNAMES_H
10
+
11
+ /* Standard Java classpath options */
12
+ #define ARG_NAME_CP "-J-cp"
13
+ #define ARG_NAME_CLASSPATH "-J-classpath"
14
+
15
+ /* These are windows-launcher-specific args. They should be prefixed with -X
16
+ so that they don't clash with normal Ruby args (like --trace for Rake). */
17
+ #define ARG_NAME_SEPAR_PROC "-Xfork-java"
18
+ #define ARG_NAME_CONSOLE "-Xconsole"
19
+ #define ARG_NAME_LAUNCHER_LOG "-Xtrace"
20
+ #define ARG_NAME_BOOTCLASS "-Xbootclass"
21
+ #define ARG_NAME_JDKHOME "-Xjdkhome"
22
+ #define ARG_NAME_CP_PREPEND "-Xcp:p"
23
+ #define ARG_NAME_CP_APPEND "-Xcp:a"
24
+ #define ARG_NAME_CMD_ONLY "-Xcommand"
25
+
26
+ /* Below are standard JRuby args handled by the launcher. */
27
+ #define ARG_NAME_SERVER "--server"
28
+ #define ARG_NAME_CLIENT "--client"
29
+ #define ARG_NAME_SAMPLE "--sample"
30
+ #define ARG_NAME_MANAGE "--manage"
31
+ #define ARG_NAME_HEADLESS "--headless"
32
+ #define ARG_NAME_PROFILE "--profile"
33
+ #define ARG_NAME_NG_SERVER "--ng-server"
34
+ #define ARG_NAME_NG "--ng"
35
+
36
+ #endif /* _ARGNAMES_H */
37
+
data/argparser.cpp ADDED
@@ -0,0 +1,559 @@
1
+ /*
2
+ * Copyright 2009-2010 JRuby Team (www.jruby.org).
3
+ */
4
+
5
+ #include <cstring>
6
+ #include <cstdlib>
7
+ #include <memory>
8
+ #include "utilsfuncs.h"
9
+ #include "argparser.h"
10
+ #include "argnames.h"
11
+
12
+ #ifndef WIN32
13
+ #include <sys/types.h>
14
+ #include <sys/utsname.h>
15
+ #include <dirent.h>
16
+ #define EXEEXT ""
17
+ #else
18
+ #define EXEEXT ".exe"
19
+ #endif
20
+
21
+ using namespace std;
22
+
23
+ const char *ArgParser::HELP_MSG =
24
+ "\nJRuby Launcher usage: jruby" EXEEXT " {options} arguments\n\
25
+ Options:\n\
26
+ -Xhelp show this help\n\
27
+ -Xjdkhome <path> path to JDK\n\
28
+ -J<jvm_option> pass <jvm_option> to JVM\n\
29
+ \n\
30
+ -Xcp <classpath> set the classpath\n\
31
+ -Xcp:p <classpath> prepend <classpath> to classpath\n\
32
+ -Xcp:a <classpath> append <classpath> to classpath\n\
33
+ \n\
34
+ -Xfork-java run java in separate process\n\
35
+ -Xtrace <path> path for launcher log (for troubleshooting)\n\
36
+ -Xcommand just print the equivalent java command and exit\n"
37
+ #ifdef WIN32
38
+ " -Xconsole <mode> jrubyw console attach mode (new|attach|suppress)\n\n"
39
+ #endif
40
+ "To see general JRuby options, type 'jruby -h' or 'jruby --help'.\n\
41
+ --------------------------------------------------------------------\n\n";
42
+
43
+ const char *ArgParser::REQ_JAVA_VERSION = "1.5";
44
+
45
+ const char *ArgParser::OPT_JDK_HOME = "-Djdk.home=";
46
+ const char *ArgParser::OPT_JRUBY_HOME = "-Djruby.home=";
47
+ const char *ArgParser::OPT_JRUBY_COMMAND_NAME = "-Dsun.java.command=";
48
+
49
+ const char *ArgParser::OPT_CLASS_PATH = "-Djava.class.path=";
50
+ const char *ArgParser::OPT_BOOT_CLASS_PATH = "-Xbootclasspath/a:";
51
+
52
+ const char *ArgParser::OPT_JFFI_PATH = "-Djffi.boot.library.path=";
53
+ const char *ArgParser::OPT_JRUBY_SHELL = "-Djruby.shell=";
54
+ const char *ArgParser::OPT_JRUBY_SCRIPT = "-Djruby.script=";
55
+ const char *ArgParser::MAIN_CLASS = "org/jruby/Main";
56
+ const char *ArgParser::DEFAULT_EXECUTABLE = "jruby";
57
+
58
+ ArgParser::ArgParser()
59
+ : separateProcess(false)
60
+ , nailgunClient(false)
61
+ , nailgunServer(false)
62
+ , printCommandLine(false)
63
+ {
64
+ }
65
+
66
+ ArgParser::ArgParser(const ArgParser& orig) {
67
+ }
68
+
69
+ ArgParser::~ArgParser() {
70
+ }
71
+
72
+ void ArgParser::addEnvVarToOptions(std::list<std::string> & optionsList, const char * envvar) {
73
+ const char * value = getenv(envvar);
74
+ string opts("");
75
+ if (value) {
76
+ opts = value;
77
+ }
78
+
79
+ if (opts.size() > 0) {
80
+ if (opts[0] == '"' || opts[0] == '\'') {
81
+ char quote = opts[0];
82
+ if (opts[opts.size() - 1] == quote) {
83
+ opts = opts.substr(1, opts.size() - 2);
84
+ }
85
+ }
86
+
87
+ size_t start = 0, pos = 0;
88
+ while ((pos = opts.find(' ', start)) != string::npos) {
89
+ string part(opts.substr(start, pos - start));
90
+ if (part.size() > 0) {
91
+ logMsg("%s += %s", envvar, part.c_str());
92
+ optionsList.push_back(part);
93
+ }
94
+ start = pos + 1;
95
+ }
96
+ if (start < opts.size()) {
97
+ string part(opts.substr(start));
98
+ if (part.size() > 0) {
99
+ logMsg("%s += %s", envvar, part.c_str());
100
+ optionsList.push_back(part);
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ #ifdef __MACH__
107
+ #include <mach-o/dyld.h>
108
+ #endif
109
+
110
+ bool ArgParser::initPlatformDir() {
111
+ #ifdef WIN32
112
+ char path[MAX_PATH] = "";
113
+ getCurrentModulePath(path, MAX_PATH);
114
+ #else
115
+ char path[PATH_MAX] = "";
116
+ bool found = false;
117
+
118
+ // first try via linux /proc/self/exe
119
+ logMsg("initPlatformDir: trying /proc/self/exe");
120
+ found = readlink("/proc/self/exe", path, PATH_MAX) != -1;
121
+
122
+ #ifdef __MACH__
123
+ uint32_t sz = PATH_MAX;
124
+ if (_NSGetExecutablePath(path, &sz) == 0) { // OSX-specific
125
+ logMsg("initPlatformDir: using _NSGetExecutablePath");
126
+ string tmpPath(path);
127
+ realpath(tmpPath.c_str(), path);
128
+ found = true;
129
+ }
130
+ #endif
131
+
132
+ #ifdef __SUNOS__
133
+ const char* execname = getexecname();
134
+ if (execname) {
135
+ logMsg("initPlatformDir: using getexecname");
136
+ char * dst = path;
137
+ if (execname[0] != '/') {
138
+ getcwd(path, PATH_MAX - strlen(execname) - 2);
139
+ dst = path + strlen(path);
140
+ *dst++ = '/';
141
+ }
142
+
143
+ strncpy(dst, execname, strlen(execname));
144
+ found = true;
145
+ }
146
+ #endif
147
+
148
+ if (!found && platformDir[0] == '/') { // argv[0]: absolute path
149
+ logMsg("initPlatformDir: argv[0] appears to be an absolute path");
150
+ strncpy(path, platformDir.c_str(), PATH_MAX);
151
+ found = true;
152
+ }
153
+
154
+ if (!found && platformDir.find('/') != string::npos) { // argv[0]: relative path
155
+ logMsg("initPlatformDir: argv[0] appears to be a relative path");
156
+ getcwd(path, PATH_MAX - platformDir.length() - 1);
157
+ strncpy(path + strlen(path), platformDir.c_str(), platformDir.length());
158
+ found = true;
159
+ }
160
+
161
+ if (!found) { // try via PATH search
162
+ logMsg("initPlatformDir: trying to find executable on PATH");
163
+ char * location = findOnPath(platformDir.c_str());
164
+ if (location != NULL) {
165
+ strncpy(path, location, PATH_MAX);
166
+ free(location);
167
+ found = true;
168
+ }
169
+ }
170
+
171
+ if (!found) { // try via JRUBY_HOME
172
+ if (getenv("JRUBY_HOME") != NULL) {
173
+ logMsg("initPlatformDir: trying JRUBY_HOME environment variable");
174
+ strncpy(path, getenv("JRUBY_HOME"), PATH_MAX - 11);
175
+ strncpy(path + strlen(path), "/bin/jruby", 10);
176
+ found = true;
177
+ }
178
+ }
179
+
180
+ if (!fileExists(path)) {
181
+ printToConsole("Could not figure out a proper location for JRuby.\n"
182
+ "Try `jruby -Xtrace trace.log ...` and view trace.log for details.");
183
+ return false;
184
+ }
185
+ #endif
186
+
187
+ logMsg("Module: %s", path);
188
+ char *bslash = strrchr(path, FILE_SEP);
189
+ if (!bslash) {
190
+ return false;
191
+ }
192
+ *bslash = '\0';
193
+ bslash = strrchr(path, FILE_SEP);
194
+ if (!bslash) {
195
+ return false;
196
+ }
197
+ *bslash = '\0';
198
+ platformDir = path;
199
+ logMsg("Platform dir: %s", platformDir.c_str());
200
+ return true;
201
+ }
202
+
203
+ bool ArgParser::parseArgs(int argc, char *argv[]) {
204
+ list<string> args;
205
+
206
+ #define CHECK_ARG \
207
+ it++; \
208
+ if (it == args.end() || it->at(0) == '-') { \
209
+ logErr(false, true, "Argument is missing for \"%s\" option.", (--it)->c_str()); \
210
+ return false; \
211
+ } \
212
+ it--;
213
+ #define INCR ++it, ++i
214
+
215
+ addEnvVarToOptions(javaOptions, "JAVA_OPTS");
216
+ addEnvVarToOptions(args, "JRUBY_OPTS");
217
+ addToArgList(args, argc, argv);
218
+
219
+ logMsg("Parsing arguments:");
220
+ for (list<string>::iterator it = args.begin(); it != args.end(); ++it) {
221
+ logMsg("\t%s", it->c_str());
222
+ }
223
+
224
+ bool doneScanning = false;
225
+
226
+ int i = 0;
227
+ for (list<string>::iterator it = args.begin(); it != args.end(); INCR) {
228
+ if (doneScanning) {
229
+ progArgs.push_back(*it);
230
+ } else if (it->compare("--") == 0 || it->at(0) != '-') {
231
+ progArgs.push_back(*it);
232
+ doneScanning = true;
233
+ } else if (it->compare(ARG_NAME_SEPAR_PROC) == 0) {
234
+ separateProcess = true;
235
+ logMsg("Run Java in separater process");
236
+ } else if (it->compare(ARG_NAME_CMD_ONLY) == 0) {
237
+ printCommandLine = true;
238
+ } else if (it->compare(ARG_NAME_LAUNCHER_LOG) == 0) {
239
+ // We only check the validity of args here,
240
+ // the actual parsing and setting the log file
241
+ // is done earlier, in checkLoggingArg()
242
+ CHECK_ARG;
243
+ INCR;
244
+ } else if (it->compare(ARG_NAME_BOOTCLASS) == 0) {
245
+ CHECK_ARG;
246
+ INCR;
247
+ bootclass = *it;
248
+ } else if (it->compare(ARG_NAME_JDKHOME) == 0) {
249
+ CHECK_ARG;
250
+ INCR;
251
+ jdkhome = *it;
252
+ } else if (it->compare(ARG_NAME_CP_PREPEND) == 0) {
253
+ CHECK_ARG;
254
+ if (!cpBefore.empty()) {
255
+ cpBefore += PATH_SEP;
256
+ }
257
+ INCR;
258
+ cpBefore += *it;
259
+ } else if (it->compare(ARG_NAME_CP_APPEND) == 0) {
260
+ CHECK_ARG;
261
+ if (!cpAfter.empty()) {
262
+ cpAfter += PATH_SEP;
263
+ }
264
+ INCR;
265
+ cpAfter += *it;
266
+ } else if (it->compare(ARG_NAME_CP) == 0
267
+ || it->compare(ARG_NAME_CLASSPATH) == 0) {
268
+ CHECK_ARG;
269
+ if (!cpExplicit.empty()) {
270
+ cpExplicit += PATH_SEP;
271
+ }
272
+ INCR;
273
+ cpExplicit += *it;
274
+ } else if (it->compare(ARG_NAME_SERVER) == 0
275
+ || it->compare(ARG_NAME_CLIENT) == 0) {
276
+ javaOptions.push_back(it->substr(1)); // to JVMLauncher, -server instead of --server
277
+ } else if (it->compare(ARG_NAME_SAMPLE) == 0) {
278
+ javaOptions.push_back("-Xprof");
279
+ } else if (it->compare(ARG_NAME_MANAGE) == 0) {
280
+ javaOptions.push_back("-Dcom.sun.management.jmxremote");
281
+ javaOptions.push_back("-Djruby.management.enabled=true");
282
+ } else if (it->compare(ARG_NAME_HEADLESS) == 0) {
283
+ javaOptions.push_back("-Djava.awt.headless=true");
284
+ } else if (it->compare(ARG_NAME_PROFILE) == 0 ||
285
+ it->compare(ARG_NAME_PROFILE "-all") == 0) {
286
+ std::string filterType = it->length() == strlen(ARG_NAME_PROFILE) ? "ruby" : "all";
287
+ javaOptions.push_front("-Dprofile.properties=" + platformDir + "/lib/profile-" + filterType + ".properties");
288
+ javaOptions.push_front("-javaagent:" + platformDir + "/lib/profile.jar");
289
+ progArgs.push_back("-X+C");
290
+ printToConsole("Running with instrumented profiler\n");
291
+ } else if (it->compare(ARG_NAME_NG) == 0) {
292
+ nailgunClient = true;
293
+ } else if (it->compare(ARG_NAME_NG_SERVER) == 0) {
294
+ bootclass = "com/martiansoftware/nailgun/NGServer";
295
+ javaOptions.push_back("-server");
296
+ nailgunServer = true;
297
+ } else if (it->compare(0, 2, "-J", 2) == 0) {
298
+ javaOptions.push_back(it->substr(2));
299
+ } else if (strcmp(it->c_str(), "-Xhelp") == 0) {
300
+ printToConsole(HELP_MSG);
301
+ if (!appendHelp.empty()) {
302
+ printToConsole(appendHelp.c_str());
303
+ }
304
+ return false;
305
+ } else {
306
+ progArgs.push_back(*it);
307
+ }
308
+ }
309
+
310
+ return true;
311
+ }
312
+
313
+ void ArgParser::prepareOptions() {
314
+ string option = OPT_JDK_HOME;
315
+ option += jdkhome;
316
+ javaOptions.push_back(option);
317
+
318
+ option = OPT_JRUBY_HOME;
319
+ option += platformDir;
320
+ javaOptions.push_back(option);
321
+
322
+ option = OPT_JRUBY_SCRIPT;
323
+ option += "jruby";
324
+ javaOptions.push_back(option);
325
+
326
+ option = OPT_JRUBY_SHELL;
327
+ #ifdef WIN32
328
+ option += "cmd.exe";
329
+ #else
330
+ const char* shell = getenv("SHELL");
331
+ if (shell == NULL) {
332
+ shell = "/bin/sh";
333
+ }
334
+ option += shell;
335
+ #endif
336
+ javaOptions.push_back(option);
337
+
338
+ option = OPT_JFFI_PATH;
339
+ #ifdef WIN32
340
+ option += (platformDir + "\\lib\\native\\i386-Windows;"
341
+ + platformDir + "\\lib\\native\\x86_64-Windows");
342
+ #else
343
+ struct utsname name;
344
+ if (uname(&name) == 0) {
345
+ string ffiPath, ffiBase(platformDir + "/lib/native");
346
+ DIR* dir = opendir(ffiBase.c_str());
347
+ struct dirent* ent;
348
+ if (dir != NULL) {
349
+ while ((ent = readdir(dir)) != NULL) {
350
+ string entry(ent->d_name);
351
+ if (entry.find(name.sysname) != string::npos) {
352
+ if (!ffiPath.empty()) {
353
+ ffiPath += PATH_SEP;
354
+ }
355
+ ffiPath += ffiBase + FILE_SEP + entry;
356
+ }
357
+ }
358
+ closedir(dir);
359
+ }
360
+ option += ffiPath;
361
+ }
362
+ #endif
363
+ javaOptions.push_back(option);
364
+
365
+ setupMaxHeapAndStack();
366
+
367
+ constructBootClassPath();
368
+ constructClassPath();
369
+
370
+ if (bootclass.empty()) {
371
+ bootclass = MAIN_CLASS;
372
+ }
373
+
374
+ // replace '/' by '.' to report a better name to jps/jconsole
375
+ string cmdName = bootclass;
376
+ size_t position = cmdName.find("/");
377
+ while (position != string::npos) {
378
+ cmdName.replace(position, 1, ".");
379
+ position = cmdName.find("/", position + 1);
380
+ }
381
+
382
+ option = OPT_JRUBY_COMMAND_NAME;
383
+ option += cmdName;
384
+ javaOptions.push_back(option);
385
+
386
+ option = OPT_CLASS_PATH;
387
+ option += classPath;
388
+ javaOptions.push_back(option);
389
+
390
+ if (!bootClassPath.empty()) {
391
+ option = OPT_BOOT_CLASS_PATH;
392
+ option += bootClassPath;
393
+ javaOptions.push_back(option);
394
+ }
395
+ }
396
+
397
+ void ArgParser::setupMaxHeapAndStack() {
398
+ // Hard-coded 500m, 1024k is for consistency with jruby shell script.
399
+ string heapSize("500m"), stackSize("1024k");
400
+ bool maxHeap = false, maxStack = false;
401
+ for (list<string>::iterator it = javaOptions.begin(); it != javaOptions.end(); it++) {
402
+ if (!maxHeap && strncmp("-Xmx", it->c_str(), 4) == 0) {
403
+ heapSize = it->substr(4, it->size() - 4);
404
+ maxHeap = true;
405
+ }
406
+ if (!maxStack && strncmp("-Xss", it->c_str(), 4) == 0) {
407
+ stackSize = it->substr(4, it->size() - 4);
408
+ maxStack = true;
409
+ }
410
+ }
411
+ if (!maxHeap) {
412
+ javaOptions.push_back("-Xmx" + heapSize);
413
+ }
414
+ if (!maxStack) {
415
+ javaOptions.push_back("-Xss" + stackSize);
416
+ }
417
+ javaOptions.push_back("-Djruby.memory.max=" + heapSize);
418
+ javaOptions.push_back("-Djruby.stack.max=" + stackSize);
419
+ }
420
+
421
+ void ArgParser::constructBootClassPath() {
422
+ logMsg("constructBootClassPath()");
423
+ addedToBootCP.clear();
424
+ addedToCP.clear();
425
+ classPath = cpBefore;
426
+
427
+ string jruby_complete_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby-complete.jar";
428
+ string jruby_jar = platformDir + FILE_SEP + "lib" + FILE_SEP + "jruby.jar";
429
+
430
+ if (fileExists(jruby_jar.c_str())) {
431
+ addToBootClassPath(jruby_jar.c_str(), true);
432
+ if (fileExists(jruby_complete_jar.c_str())) {
433
+ printToConsole("WARNING: Both jruby-complete.jar and jruby.jar are present in the 'lib' directory. Will use jruby.jar\n");
434
+ }
435
+ } else if (fileExists(jruby_complete_jar.c_str())) {
436
+ addToBootClassPath(jruby_complete_jar.c_str());
437
+ }
438
+
439
+ logMsg("BootclassPath: %s", bootClassPath.c_str());
440
+ }
441
+
442
+ void ArgParser::constructClassPath() {
443
+ logMsg("constructClassPath()");
444
+
445
+ addJarsToClassPathFrom(platformDir.c_str());
446
+
447
+ if (cpExplicit.empty()) {
448
+ logMsg("No explicit classpath option is used, looking up %%CLASSPATH%% env");
449
+ char *envCP = getenv("CLASSPATH");
450
+ if (envCP) {
451
+ addToClassPath(envCP, false);
452
+ }
453
+ } else {
454
+ logMsg("Explicit classpath option is used, ignoring %%CLASSPATH%% env");
455
+ addToClassPath(cpExplicit.c_str(), false);
456
+ }
457
+
458
+ if (!cpAfter.empty()) {
459
+ classPath += PATH_SEP;
460
+ classPath += cpAfter;
461
+ }
462
+
463
+ logMsg("ClassPath: %s", classPath.c_str());
464
+ }
465
+
466
+ void ArgParser::addJarsToClassPathFrom(const char *dir) {
467
+ logMsg("addJarsToClassPathFrom()\n\tdir: %s", dir);
468
+ string path = dir;
469
+ path += FILE_SEP;
470
+ path += "lib";
471
+
472
+ #ifdef WIN32
473
+ WIN32_FIND_DATA fd = {0};
474
+ string patternPath = path + FILE_SEP + "*.jar";
475
+ HANDLE hFind = FindFirstFile(patternPath.c_str(), &fd);
476
+ if (hFind == INVALID_HANDLE_VALUE) {
477
+ logMsg("Nothing found (%s)", patternPath.c_str());
478
+ return;
479
+ }
480
+ do {
481
+ string fullName = path + FILE_SEP + fd.cFileName;
482
+ addToClassPath(fullName.c_str());
483
+ } while (FindNextFile(hFind, &fd));
484
+ FindClose(hFind);
485
+ #else
486
+ DIR *directory = opendir(path.c_str());
487
+ if (!directory) {
488
+ logMsg("Nothing found (%s)", path.c_str());
489
+ return;
490
+ }
491
+
492
+ struct dirent *ent;
493
+ while((ent = readdir(directory)) != NULL) {
494
+ int len = strlen(ent->d_name);
495
+ if (len > 4 && strncmp(".jar", (ent->d_name + (len - 4)), 4) == 0) {
496
+ string fullName = path + FILE_SEP + ent->d_name;
497
+ addToClassPath(fullName.c_str());
498
+ }
499
+ }
500
+ closedir(directory);
501
+ #endif
502
+ }
503
+
504
+ void ArgParser::addToClassPath(const char *path, bool onlyIfExists) {
505
+ logMsg("addToClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
506
+ if (onlyIfExists && !fileExists(path)) {
507
+ return;
508
+ }
509
+
510
+ if (!addedToCP.insert(path).second) {
511
+ logMsg("\"%s\" already added, skipping", path);
512
+ return;
513
+ }
514
+
515
+ // check that this hasn't been added to boot class path already
516
+ if (addedToBootCP.find(path) == addedToBootCP.end()) {
517
+ if (!classPath.empty()) {
518
+ classPath += PATH_SEP;
519
+ }
520
+ classPath += path;
521
+ } else {
522
+ logMsg("No need to add \"%s\" to classpath, it's already in bootclasspath", path);
523
+ }
524
+ }
525
+
526
+ void ArgParser::addToBootClassPath(const char *path, bool onlyIfExists) {
527
+ logMsg("addToBootClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, onlyIfExists ? "true" : "false");
528
+
529
+ if (nailgunServer) {
530
+ logMsg("NOTE: In 'ng-server' mode there is no bootclasspath, adding to classpath...");
531
+ return addToClassPath(path, onlyIfExists);
532
+ }
533
+
534
+ if (onlyIfExists && !fileExists(path)) {
535
+ return;
536
+ }
537
+
538
+ // only add non-duplicates
539
+ if (addedToBootCP.insert(path).second) {
540
+ if (!bootClassPath.empty()) {
541
+ bootClassPath += PATH_SEP;
542
+ }
543
+ bootClassPath += path;
544
+ } else {
545
+ logMsg("\"%s\" already in bootclasspath", path);
546
+ }
547
+ }
548
+
549
+ void ArgParser::appendToHelp(const char *msg) {
550
+ if (msg) {
551
+ appendHelp = msg;
552
+ }
553
+ }
554
+
555
+ void ArgParser::addOptionsToCommandLine(list<string> & commandLine) {
556
+ commandLine.insert(commandLine.end(), javaOptions.begin(), javaOptions.end());
557
+ commandLine.insert(commandLine.end(), bootclass);
558
+ commandLine.insert(commandLine.end(), progArgs.begin(), progArgs.end());
559
+ }