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/COPYING +826 -0
- data/Makefile +106 -0
- data/README.txt +61 -0
- data/Rakefile +27 -0
- data/argnames.h +37 -0
- data/argparser.cpp +559 -0
- data/argparser.h +76 -0
- data/extconf.rb +6 -0
- data/inc/Makefile-conf.mk +75 -0
- data/inc/Makefile-impl.mk +107 -0
- data/inc/Makefile-rules.mk +40 -0
- data/jruby.cpp +77 -0
- data/jrubyexe.cpp +84 -0
- data/jvmlauncher.cpp +421 -0
- data/jvmlauncher.h +141 -0
- data/lib/jruby-launcher.rb +3 -0
- data/lib/rubygems/defaults/jruby_native.rb +4 -0
- data/nbexecloader.h +43 -0
- data/ng.c +642 -0
- data/platformlauncher.cpp +239 -0
- data/platformlauncher.h +73 -0
- data/rb_w32_cmdvector.h +287 -0
- data/resources/jruby.ico +0 -0
- data/resources/jruby.rc +25 -0
- data/spec/launcher_spec.rb +134 -0
- data/spec/spec_helper.rb +61 -0
- data/strlcpy.c +69 -0
- data/unixlauncher.cpp +81 -0
- data/unixlauncher.h +22 -0
- data/utilsfuncs.cpp +269 -0
- data/utilsfuncs.h +84 -0
- data/utilsfuncswin.cpp +229 -0
- metadata +96 -0
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
|
+
}
|