1 #include "Builders.h"
2 
AdjustLines(const String & file)3 String AdjustLines(const String& file)
4 {
5 	String out;
6 	const char *p = file;
7 	while(*p)
8 	{
9 		const char *b = p;
10 		while(*p && (byte)*p <= ' ' && *p != '\r' && *p != '\n')
11 			p++;
12 		if(*p == '#')
13 		{
14 			out.Cat("//");
15 			b = p;
16 			while(*p && *p != '\n' && *p != '\"')
17 				p++;
18 			out.Cat(b, (int)(p - b));
19 			b = p;
20 			if(*p == '\"')
21 			{
22 				out.Cat('\"');
23 				b = ++p;
24 				while(*p && *p++ != '\n')
25 					;
26 				const char *e = p;
27 				while(e > b && (byte)e[-1] <= ' ')
28 					e--;
29 				if(e[-1] == '\"')
30 					e--;
31 				out.Cat(UnixPath(String(b, e)));
32 				out.Cat("\"\r\n");
33 				b = p;
34 				continue;
35 			}
36 		}
37 		out.Cat(b, (int)(p - b));
38 		while(*p && *p != '\n')
39 		{
40 			b = p;
41 			while(*p && *p != '\n' && *p != '\r')
42 				p++;
43 			out.Cat(b, (int)(p - b));
44 			while(*p == '\r')
45 				p++;
46 		}
47 		if(*p == '\n')
48 		{
49 			p++;
50 			out.Cat("\r\n");
51 		}
52 	}
53 	return out;
54 }
55 
JavaLine()56 String JavaBuilder::JavaLine()
57 {
58 	return "javac";
59 }
60 
JarLine()61 String JavaBuilder::JarLine()
62 {
63 	return "jar";
64 }
65 
66 enum { MAINCLASS, MAINDIR, MANIFEST, ITEMCOUNT };
67 
BuildPackage(const String & package,Vector<String> & linkfile,Vector<String> &,String & linkoptions,const Vector<String> & all_uses,const Vector<String> & all_libraries,int)68 bool JavaBuilder::BuildPackage(const String& package, Vector<String>& linkfile, Vector<String>&, String& linkoptions,
69 	const Vector<String>& all_uses, const Vector<String>& all_libraries, int)
70 {
71 	int time = msecs();
72 	int i;
73 	int manifest = -1;
74 	String packagepath = PackagePath(package);
75 	Package pkg;
76 	pkg.Load(packagepath);
77 	String packagedir = GetFileFolder(packagepath);
78 	ChDir(packagedir);
79 	PutVerbose("cd " + packagedir);
80 	Vector<String> pkgsfile;
81 	Vector<String> sfile;
82 	Vector<String> sobjfile;
83 	Vector<String> soptions;
84 	bool           error = false;
85 	bool main = HasFlag("MAIN");
86 
87 	for(i = 0; i < pkg.GetCount(); i++) {
88 		if(!IdeIsBuilding())
89 			return false;
90 		if(!pkg[i].separator) {
91 			String gop = Gather(pkg[i].option, config.GetKeys());
92 			Vector<String> srcfile = CustomStep(pkg[i], package, error);
93 			if(srcfile.GetCount() == 0)
94 				error = true;
95 			for(int j = 0; j < srcfile.GetCount(); j++)
96 			{
97 				String fn = srcfile[j];
98 				String ext = ToLower(GetFileExt(fn));
99 				bool ismf = false;
100 				if(ext == ".java" || main && ext == ".mf")
101 				{
102 					if(ext == ".mf")
103 					{
104 						ismf = true;
105 						if(manifest >= 0)
106 						{
107 							PutConsole(Format("%s(1): duplicate manifest file", GetHostPath(fn)));
108 							PutConsole(Format("%s(1): (previous manifest file)", GetHostPath(sfile[manifest])));
109 						}
110 						manifest = sfile.GetCount();
111 					}
112 					String pkgfile = AppendFileName(package, pkg[i]);
113 					pkgsfile.Add(pkgfile);
114 					sfile.Add(fn);
115 					soptions.Add(gop);
116 					String objfile = NativePath(CatAnyPath(outdir, ismf ? String("manifest.mf") : pkgfile));
117 					sobjfile.Add(objfile);
118 				}
119 			}
120 		}
121 	}
122 
123 	Vector<Host::FileInfo> sobjinfo = host->GetFileInfo(sobjfile);
124 	int ccount = 0;
125 	for(i = 0; i < sfile.GetCount(); i++) {
126 		if(!IdeIsBuilding())
127 			return false;
128 		if(HdependFileTime(sfile[i]) > sobjinfo[i]) {
129 			ccount++;
130 			if(!PreprocessJava(sfile[i], sobjfile[i], soptions[i], package, pkg))
131 				error = true;
132 		}
133 	}
134 	linkfile.Add(outdir);
135 	if(ccount > 0)
136 		PutConsole(String().Cat() << ccount << " file(s) preprocessed in " << GetPrintTime(time) <<
137 		           " " << int(msecs() - time) / ccount << " msec/file");
138 	linkoptions << ' ' << Gather(pkg.link, config.GetKeys());
139 
140 	if(!error && HasFlag("MAIN") && !sfile.IsEmpty())
141 	{
142 		String mainfile = sfile.Top();
143 		String mainobj = sobjfile.Top();
144 		String maincls = ForceExt(mainobj, ".class");
145 		String libs;
146 		int i;
147 		for(i = 0; i < libpath.GetCount(); i++)
148 			libs << (i ? ";" : " -classpath ") << '\"' << libpath[i] << '\"';
149 		String linkcmd;
150 		linkcmd << "javac";
151 		linkcmd << (HasFlag("DEBUG") ? " -g" : " -g:none");
152 		if(!HasFlag("DEBUG")) {
153 			if(!IsNull(release_options))
154 				linkcmd << ' ' << release_options;
155 			else
156 				linkcmd << " -O";
157 		}
158 		linkcmd << " -deprecation" << linkoptions << " -sourcepath ";
159 		bool win32 = HasFlag("WIN32");
160 		for(i = 0; i < linkfile.GetCount(); i++) {
161 			linkcmd << (i ? (win32 ? ";" : ":") : "");
162 			if(linkfile[i].Find(' ') >= 0)
163 				linkcmd << '\"' << linkfile[i] << '\"';
164 			else
165 				linkcmd << linkfile[i];
166 		}
167 		linkfile.InsertN(0, ITEMCOUNT);
168 		linkfile[MAINCLASS] = maincls;
169 		linkfile[MAINDIR] = outdir;
170 		linkfile[MANIFEST] = (manifest >= 0 ? sobjfile[manifest] : String());
171 		linkcmd << ' ' << mainobj;
172 		linkoptions = linkcmd;
173 	}
174 	return !error;
175 }
176 
Preprocess(const String & package,const String & file,const String & target,bool)177 bool JavaBuilder::Preprocess(const String& package, const String& file, const String& target, bool)
178 {
179 	return Builder::Preprocess(file, target, Null, false);
180 }
181 
PreprocessJava(String file,String target,String options,String package,const Package & pkg)182 bool JavaBuilder::PreprocessJava(String file, String target, String options,
183                                  String package, const Package& pkg)
184 {
185 	String mscpp = GetVar("MSCPP_JDK");
186 	String cc;
187 	if(!IsNull(mscpp))
188 		cc = mscpp + " /C /TP /P /nologo ";
189 	else
190 		cc = "cpp -C ";
191 	cc << IncludesDefinesTargetTime(package, pkg);
192 	int time = msecs();
193 	RealizePath(target);
194 	String execpath;
195 	execpath << cc << ' ' << options << ' ';
196 	String prepfile;
197 	bool error = false;
198 	if(!IsNull(mscpp))
199 	{
200 		prepfile = ForceExt(file, ".i");
201 		host->ChDir(GetFileFolder(prepfile));
202 		execpath << GetHostPath(file);
203 	}
204 	else
205 	{
206 		PutConsole(file);
207 		execpath << GetHostPath(file) << " " << GetHostPath(target);
208 		prepfile = target;
209 	}
210 	if(Execute(execpath) != 0)
211 	{
212 		DeleteFile(target);
213 		error = true;
214 	}
215 	String prep = LoadFile(prepfile);
216 	if(prep.IsEmpty())
217 	{
218 		PutConsole(Format("Error loading preprocessed file %s", prepfile));
219 		error = true;
220 	}
221 	DeleteFile(prepfile);
222 	if(!prep.IsEmpty() && !::SaveFile(target, AdjustLines(prep)))
223 	{
224 		DeleteFile(target);
225 		error = true;
226 		PutConsole(Format("%s: error saving file.", target));
227 	}
228 	PutVerbose("preprocessed in " + GetPrintTime(time));
229 	return !error;
230 }
231 
AddClassDeep(String & link,String dir,String reldir)232 Time JavaBuilder::AddClassDeep(String& link, String dir, String reldir)
233 {
234 	Time time = Time::Low();
235 	Vector<String> folders;
236 	for(FindFile ff(AppendFileName(dir, AppendFileName(reldir, "*"))); ff; ff.Next()) {
237 		if(ff.IsFolder())
238 			folders.Add(ff.GetName());
239 		else if(!stricmp(GetFileExtPos(ff.GetName()), ".class"))
240 		{
241 			link << " -C \"" << dir << "\" \"" << UnixPath(CatAnyPath(reldir, ff.GetName())) << '\"';
242 			time = max(time, Time(ff.GetLastWriteTime()));
243 		}
244 	}
245 	for(int f = 0; f < folders.GetCount(); f++)
246 		time = max(time, AddClassDeep(link, dir, AppendFileName(reldir, folders[f])));
247 	return time;
248 }
249 
Link(const Vector<String> & linkfile,const String & linkoptions,bool)250 bool JavaBuilder::Link(const Vector<String>& linkfile, const String& linkoptions, bool)
251 {
252 	if(linkfile.GetCount() < ITEMCOUNT)
253 		return false;
254 	int time = msecs();
255 	String mainclass = linkfile[MAINCLASS];
256 	String maindir = linkfile[MAINDIR];
257 	String manifest = linkfile[MANIFEST];
258 	PutConsole("Compiling...");
259 	if(Execute(linkoptions) != 0) {
260 		DeleteFile(mainclass);
261 		return false;
262 	}
263 	PutVerbose("compiled in " + GetPrintTime(time));
264 	host->ChDir(maindir);
265 
266 	PutConsole("Archiving...");
267 	String cmdline;
268 	cmdline << "cf";
269 	if(!manifest.IsEmpty())
270 		cmdline << 'm';
271 	cmdline << ' ' << GetHostPath(target);
272 	if(!manifest.IsEmpty())
273 		cmdline << ' ' << GetHostPath(manifest);
274 	Time tm = Time::Low();
275 	for(int i = ITEMCOUNT; i < linkfile.GetCount(); i++)
276 		tm = max(tm, AddClassDeep(cmdline, linkfile[i], Null));
277 	bool error = false;
278 	if(tm > targettime) {
279 		CustomStep(".pre-link", Null, error);
280 		String link, response;
281 		link << "jar ";
282 		if(cmdline.GetLength() < 32000)
283 			link << cmdline;
284 		else {
285 			response = GetTempFileName("jar");
286 			link << '@' << response;
287 			if(!UPP::SaveFile(response, cmdline)) {
288 				PutConsole(String().Cat() << "Error writing JAR response file '" << response << "'");
289 				return false;
290 			}
291 		}
292 		bool ok = (Execute(link) == 0);
293 		if(!IsNull(response))
294 			FileDelete(response);
295 		if(!ok) {
296 			DeleteFile(target);
297 			return false;
298 		}
299 		CustomStep(".post-link", Null, error);
300 		PutConsole(String().Cat() << target << " (" << GetFileInfo(target).length
301 		           << " B) archived in " << GetPrintTime(time));
302 	}
303 	else
304 		PutConsole(String().Cat() << GetHostPath(target) << " (" << GetFileInfo(target).length
305 		           << " B) is up to date.");
306 	return true;
307 }
308 
CreateJavaBuilder()309 static Builder *CreateJavaBuilder()
310 {
311 	return new JavaBuilder;
312 }
313 
INITIALIZER(JavaBuilder)314 INITIALIZER(JavaBuilder)
315 {
316 	RegisterBuilder("JDK", &CreateJavaBuilder);
317 }
318