SystemCall run(block) can now exit the run if it returns false
[io/quag.git] / build / AddonBuilder.io
blobed67a7a15cd14ff2a6acbd5fefefaec658724af5
1 Sequence prepend := method(s, s .. self)
3 AddonBuilder := Object clone do(
4 isDisabled := false
5 disable := method(isDisabled = true)
7 platform := System platform split at(0) asLowercase
8 cflags := method(System getenv("CFLAGS") ifNilEval(""))
9 if (platform == "windows",
10 cc := method(System getenv("CC") ifNilEval(return "cl -nologo"))
11 cxx := method(System getenv("CXX") ifNilEval(return "cl -nologo"))
12 ccOutFlag := "-Fo"
13 linkdll := "link -link -nologo"
14 linkDirPathFlag := "-libpath:"
15 linkLibFlag := "lib"
16 linkOutFlag := "-out:"
17 linkLibSuffix := ".lib"
18 ar := "link -lib -nologo"
19 arFlags := "-out:"
20 ranlib := nil
22 cc := method(System getenv("CC") ifNilEval(return "cc"))
23 cxx := method(System getenv("CXX") ifNilEval(return "g++"))
24 ccOutFlag := "-o "
25 linkdll := cc
26 linkDirPathFlag := "-L"
27 linkLibFlag := "-l"
28 linkLibSuffix := ""
29 linkOutFlag := "-o "
30 linkLibSuffix := ""
31 ar := method(System getenv("AR") ifNilEval(return "ar"))
32 arFlags := "rcu "
33 ranlib := method(System getenv("RANLIB") ifNilEval(return "ranlib"))
36 supportedOnPlatform := true
38 frameworkSearchPaths := List clone
39 frameworkSearchPaths append("/System/Library/Frameworks")
40 frameworkSearchPaths append("/Library/Frameworks")
41 frameworkSearchPaths append("/Local/Library/Frameworks")
42 // frameworkSearchPaths append("~/Library/Frameworks")
44 searchPrefixes := List clone
45 searchPrefixes append(System installPrefix)
46 searchPrefixes append("/usr")
47 searchPrefixes append("/mingw")
48 searchPrefixes append("/usr/X11R6")
49 searchPrefixes append("/usr/local")
50 searchPrefixes append("/usr/pkg")
51 searchPrefixes append("/opt/local")
52 searchPrefixes append("/sw")
53 // on windows there is no such thing as a standard place
54 // to look for these things
55 searchPrefixes append("i:/io/addonLibs")
57 headerSearchPaths := List clone
58 appendHeaderSearchPath := method(v, if(File clone setPath(v) exists, headerSearchPaths appendIfAbsent(v)))
59 searchPrefixes foreach(searchPrefix, appendHeaderSearchPath(searchPrefix .. "/include"))
61 libSearchPaths := List clone
62 appendLibSearchPath := method(v, if(File clone setPath(v) exists, libSearchPaths appendIfAbsent(v)))
63 searchPrefixes foreach(searchPrefix, appendLibSearchPath(searchPrefix .. "/lib"))
65 debs := Map clone
66 ebuilds := Map clone
67 pkgs := Map clone
68 rpms := Map clone
70 init := method(
71 self folder := Directory clone
73 self depends := Object clone do(
74 headers := List clone
75 libs := List clone
76 frameworks := List clone
77 syslibs := List clone
78 includes := List clone
79 linkOptions := List clone
80 addons := List clone
84 mkdir := method(relativePath,
85 if (folder path != ".",
86 path := folder path .. "/" .. relativePath
88 if(Directory exists(path) not,
89 writeln("mkdir -p ", relativePath)
90 dir := Directory with(".")
91 path split("/") foreach(x, dir := dir folderNamedCreateIfAbsent(x))
95 pathForFramework := method(name,
96 frameworkname := name .. ".framework"
97 path := frameworkSearchPaths detect(path,
98 Directory with(path .. "/" .. frameworkname) exists
100 path
103 pathForHeader := method(name,
104 path := headerSearchPaths detect(path,
105 File with(path .. "/" .. name) exists
107 path
110 pathForLib := method(name,
111 libname := "lib" .. name
112 path := libSearchPaths detect(path,
113 p1 := File with(path .. "/" .. libname .. "." .. dllSuffix) exists
114 p2 := File with(path .. "/" .. libname .. ".a") exists
115 p3 := File with(path .. "/" .. libname .. ".lib") exists
116 p1 or p2 or p3
118 path
121 dependsOnBinding := method(v, depends addons appendIfAbsent(v))
122 dependsOnHeader := method(v, depends headers appendIfAbsent(v))
123 dependsOnLib := method(v, depends libs appendIfAbsent(v))
124 dependsOnFramework := method(v, depends frameworks appendIfAbsent(v))
125 dependsOnInclude := method(v, depends includes appendIfAbsent(v))
126 dependsOnLinkOption := method(v, depends linkOptions appendIfAbsent(v))
127 dependsOnSysLib := method(v, depends syslibs appendIfAbsent(v))
129 dependsOnFrameworkOrLib := method(v, w,
130 path := pathForFramework(v)
131 if(path != nil, dependsOnFramework(v) ; appendHeaderSearchPath(path .. "/" .. v .. ".framework/Headers"), dependsOnLib(w))
134 optionallyDependsOnLib := method(v, if(pathForLib(v) != nil, dependsOnLib(v)))
135 optionallyDependsOnFramework := method(v, if(pathForFramework(v) != nil, dependsOnFramework(v)))
137 missingFrameworks := method(
138 depends frameworks select(p,
139 if(pathForFramework(p) == nil,
140 error := (self name .. " is missing " .. p .. " framework\n") print
141 File clone openForAppending("errors") write(error) close
142 self isAvailable := false
143 true
148 missingHeaders := method(
149 depends headers select(p,
150 if(pathForHeader(p) == nil,
151 error := (self name .. " is missing " .. p .. " header\n") print
152 File clone openForAppending("errors") write(error) close
153 self isAvailable := false
154 true
159 missingLibs := method(
160 depends libs select(p,
161 //writeln("pathForLib(", p, ") = ", pathForLib(p))
162 if(pathForLib(p) == nil,
163 error := (self name .. " is missing " .. p .. " library\n") print
164 File clone openForAppending("errors") write(error) close
165 self isAvailable := false
166 true
171 hasDepends := method(missingFrameworks size == 0 and missingLibs size == 0 and missingHeaders size == 0)
173 installCommands := method(
174 commands := Map clone
175 missingLibs foreach(p,
176 if(debs at(p), commands atPut("apt-get", "apt-get install " .. debs at(p) .. " && ldconfig"))
177 if(ebuilds at(p), commands atPut("emerge", "emerge -DN1 " .. ebuilds at(p)))
178 if(pkgs at(p), commands atPut("port", "port install " .. pkgs at(p)))
179 if(rpms at(p), commands atPut("urpmi", "urpmi " .. rpms at(p) .. " && ldconfig"))
181 commands
184 with := method(path,
185 module := self clone
186 module folder setPath(path)
187 module
190 systemCall := method(s,
191 if(trySystemCall(s) == 256, System exit(1))
194 trySystemCall := method(s,
195 writeln(s)
196 oldPath := nil
197 if (folder path != ".",
198 oldPath := Directory currentWorkingDirectory
199 Directory setCurrentWorkingDirectory(folder path)
201 result := System system(s)
202 if (oldPath != nil,
203 Directory setCurrentWorkingDirectory(oldPath)
205 result
208 // ------------------------------------
210 name := method(folder name)
211 oldDate := Date clone setYear(1970)
213 libName := method("libIo" .. folder name .. ".a")
215 libFile := method(folder fileNamedOrNil(libName))
216 objsFolder := method(self objsFolder := folder createSubdirectory("_build/objs"))
217 sourceFolder := method(folder folderNamed("source"))
218 cFiles := method(
219 sourceFolder filesWithExtension("cpp") appendSeq(sourceFolder filesWithExtension("c")) appendSeq(sourceFolder filesWithExtension("m"))
222 libsFolder := method(Directory with("libs"))
223 addonsFolder := method(Directory with("addons"))
225 includePaths := method(
226 includePaths := List clone
227 includePaths appendSeq(libsFolder folders map(path) map(p, Path with(p, "_build/headers")))
228 includePaths appendSeq(depends addons map(n, "addons/" .. n .. "/_build/headers"))
229 includePaths
232 build := method(options,
233 writeln(("--- " .. folder name .. " ") alignLeft(79, "-"))
234 writeln("build.io: Entering directory `", folder path, "'")
235 mkdir("_build/headers")
236 if(Directory with(Path with(folder path, "source")) filesWithExtension(".h") size > 0,
237 trySystemCall("cp source/*.h _build/headers")
240 generateInitFile
242 options := options ifNilEval("") .. cflags
243 cFiles foreach(f,
244 obj := f name replaceSeq(".cpp", ".o") replaceSeq(".c", ".o") replaceSeq(".m", ".o")
245 objFile := objsFolder fileNamedOrNil(obj)
246 if((objFile == nil) or(objFile lastDataChangeDate < f lastDataChangeDate),
248 includes := includePaths map(v, "-I" .. Path with("../../", v))
249 includes appendSeq(headerSearchPaths map(v, "-I" .. v))
251 s := cc .. " " .. options .. " " .. depends includes join(" ") .. " " .. includes join(" ") .. " -I. "
252 if(list("cygwin", "mingw", "windows") contains(platform) not,
253 s = s .. "-fPIC "
255 s = s .. "-DBUILDING_"
256 s = s .. name asUppercase
257 s = s .. "_ADDON "
259 s = s .. "-c " .. ccOutFlag .. "_build/objs/" .. obj .. " source/" .. f name
260 systemCall(s)
264 buildLib
265 buildDynLib
266 if(platform == "windows", embedManifest)
267 writeln("build.io: Leaving directory `", folder path, "'")
268 writeln
271 buildLib := method(
272 mkdir("_build/lib")
273 systemCall(ar .. " " .. arFlags .. "_build/lib/" .. libName .. " _build/objs/*.o")
274 if (ranlib != nil, systemCall(ranlib .. " _build/lib/" .. libName))
277 dllSuffix := method(
278 if(list("cygwin", "mingw", "windows") contains(platform), return "dll")
279 if(platform == "darwin", return "dylib")
280 "so"
283 dllNameFor := method(s, "lib" .. s .. "." .. dllSuffix)
285 dllCommand := method(
286 if(platform == "darwin",
287 "-dynamiclib -single_module -read_only_relocs suppress"
289 if (platform == "windows",
290 "-dll -debug"
292 "-shared"
297 buildDynLib := method(
298 mkdir("_build/dll")
300 links := depends addons map(b, linkDirPathFlag .. "../" .. b .. "/_build/dll")
302 links appendSeq(depends addons map(v, linkLibFlag .. "Io" .. v .. linkLibSuffix))
303 if(platform == "windows",
304 links appendSeq(depends syslibs map(v, v .. ".lib"))
306 if(platform != "darwin" and platform != "windows",
307 links appendSeq(depends addons map(v, "-Wl,--rpath -Wl," .. System installPrefix .. "/lib/io/addons/" .. v .. "/_build/dll/"))
309 links appendSeq(libSearchPaths map(v, linkDirPathFlag .. v))
310 links appendSeq(depends libs map(v, linkLibFlag .. v .. linkLibSuffix))
311 links appendSeq(list(linkDirPathFlag .. "../../_build/dll", linkLibFlag .. "iovmall" .. linkLibSuffix))
313 links appendSeq(depends frameworks map(v, "-framework " .. v))
314 links appendSeq(depends linkOptions)
316 libname := dllNameFor("Io" .. self name)
318 s := ""
319 if(platform == "darwin",
320 links append("-flat_namespace")
321 s := " -install_name " .. System installPrefix .. "/lib/io/addons/" .. self name .. "/_build/dll/" .. libname
324 systemCall(linkdll .. " " .. cflags .. " " .. dllCommand .. " " .. s .. " " .. linkOutFlag .. "_build/dll/" .. libname .. " _build/objs/*.o" .. " " .. links join(" "))
327 embedManifest := method(
328 dllFilePath := "_build/dll/" .. dllNameFor("Io" .. name)
329 manifestFilePath := dllFilePath .. ".manifest"
330 systemCall("mt.exe -manifest " .. manifestFilePath .. " -outputresource:" .. dllFilePath .. ";2")
331 writeln("Removing manifest file: " .. manifestFilePath)
332 File with(folder path .. "/" .. manifestFilePath) remove
335 clean := method(
336 writeln(folder name, " clean")
337 trySystemCall("rm -rf _build")
338 trySystemCall("rm -f source/Io*Init.c")
339 self removeSlot("objsFolder")
342 ioCodeFolder := method(folder folderNamed("io"))
343 ioFiles := method(ioCodeFolder filesWithExtension("io"))
344 initFileName := method("source/Io" .. folder name .. "Init.c")
346 isStatic := false
348 generateInitFile := method(
349 if(folder folderNamed("source") filesWithExtension("m") size != 0, return)
350 initFile := folder createFileNamed(initFileName)
351 initFile remove open
352 initFile write("#include \"IoState.h\"\n")
353 initFile write("#include \"IoObject.h\"\n\n")
355 sourceFiles := folder folderNamed("source") files
356 iocFiles := sourceFiles select(f, f name beginsWithSeq("Io") and(f name endsWithSeq(".c")) and(f name containsSeq("Init") not) and(f name containsSeq("_") not))
357 iocppFiles := sourceFiles select(f, f name beginsWithSeq("Io") and(f name endsWithSeq(".cpp")) and(f name containsSeq("Init") not) and(f name containsSeq("_") not))
359 iocFiles appendSeq(iocppFiles)
360 extraFiles := sourceFiles select(f, f name beginsWithSeq("Io") and(f name endsWithSeq(".c")) and(f name containsSeq("Init") not) and(f name containsSeq("_")))
362 orderedFiles := List clone appendSeq(iocFiles)
364 iocFiles foreach(f,
365 d := f open readLines detect(line, line containsSeq("docDependsOn"))
366 f close
368 if(d,
369 prerequisitName := "Io" .. d afterSeq("(\"") beforeSeq("\")") .. ".c"
370 prerequisit := orderedFiles detect(of, of name == prerequisitName )
371 orderedFiles remove(f)
372 orderedFiles insertAfter(f, prerequisit)
376 iocFiles = orderedFiles
378 iocFiles foreach(f,
379 initFile write("IoObject *" .. f name fileName .. "_proto(void *state);\n")
382 extraFiles foreach(f,
383 initFile write("void " .. f name fileName .. "Init(void *context);\n")
386 if (platform == "windows",
387 initFile write("__declspec(dllexport)\n")
389 initFile write("\nvoid Io" .. folder name .. "Init(IoObject *context)\n")
390 initFile write("{\n")
391 if(iocFiles size > 0,
392 initFile write("\tIoState *self = IoObject_state((IoObject *)context);\n\n")
395 iocFiles foreach(f,
396 initFile write("\tIoObject_setSlot_to_(context, SIOSYMBOL(\"" .. f name fileName asMutable removePrefix("Io") .. "\"), " .. f name fileName .. "_proto(self));\n\n")
399 extraFiles foreach(f,
400 initFile write("\t" .. f name fileName .. "Init(context);\n")
403 if(ioCodeFolder and isStatic,
404 ioFiles foreach(f, initFile write(codeForIoFile(f)))
407 initFile write("}\n")
408 initFile close
411 codeForIoFile := method(f,
412 code := Sequence clone
413 if (f size > 0,
414 code appendSeq("\t{\n\t\tchar *s = ")
415 code appendSeq(f contents splitNoEmpties("\n") map(line, "\"" .. line escape .. "\\n\"") join("\n\t\t"))
416 code appendSeq(";\n\t\tIoState_on_doCString_withLabel_(self, context, s, \"" .. f name .. "\");\n")
417 code appendSeq("\t}\n\n")
419 code
422 generateDocs := method(
423 systemCall("../../_build/binaries/io ../../tools/io/DocsExtractor.io .")
426 cleanDocs := method(
427 systemCall("rm -f io/zzz_docs.io")