summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/genie/src/actions/ninja/ninja_swift_incremental.lua
blob: 2168d18b3fe73cf4d74dda700dea12cea97b6bb4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
--
-- Generates Ninja project file for Swift
-- Copyright (c) 2016 Stuart Carnie and the GENie project
--

local ninja = premake.ninja
local swift = { }
local p     = premake

-- generate project + config build using incremental approach of generating individual .o files
function ninja.generate_swift_incremental(prj)
	local pxy = ninja.get_proxy("prj", prj)
	local tool = premake.gettool(prj)

	-- build a list of supported target platforms that also includes a generic build
	local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native")

	for _, platform in ipairs(platforms) do
		for cfg in p.eachconfig(pxy, platform) do
			p.generate(cfg, cfg:getprojectfilename(), function() swift.generate_config(prj, cfg) end)
		end
	end
end

function swift.generate_config(prj, cfg)
	local tool = premake.gettool(prj)

	local flags = {
		swiftcflags = ninja.list(table.join(tool.getswiftcflags(cfg), cfg.buildoptions_swiftc)),
	}


	_p("# Swift project build file")
	_p("# generated with GENie ninja")
	_p("")

	-- needed for implicit outputs, introduced in 1.7
	_p("ninja_required_version = 1.7")
	_p("")

	_p("out_dir = %s", cfg.buildtarget.directory)
	_p("obj_dir = %s", path.join(cfg.objectsdir, prj.name .. ".build"))
	_p("module_name = %s", prj.name)
	_p("module_maps = %s", ninja.list(tool.getmodulemaps(cfg)))
	_p("swiftc_flags = %s", flags.swiftcflags)
	_p("swiftlink_flags = %s", flags.swiftlinkflags)
	_p("ar_flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false)))

	local sdk = tool.get_sdk_path(cfg)
	if sdk then
		_p("toolchain_path = %s", tool.get_toolchain_path(cfg))
		_p("sdk_path = %s", sdk)
		_p("platform_path = %s", tool.get_sdk_platform_path(cfg))
		_p("sdk = -sdk $sdk_path")
		_p("ld_baseflags = -force_load $toolchain_path/usr/lib/arc/libarclite_macosx.a -L $out_dir -F $platform_path/Developer/Library/Frameworks -syslibroot $sdk_path -lobjc -lSystem -L $toolchain_path/usr/lib/swift/macosx -rpath $toolchain_path/usr/lib/swift/macosx -macosx_version_min 10.10.0 -no_objc_category_merging")
	else
		_p("sdk_path =")
		_p("sdk =")
		_p("ld_baseflags =")
	end
	_p("")

	_p("# core rules for %s", cfg.name)
	_p("rule swiftc")
	_p(1, "command = %s -frontend -c -primary-file $in $files $target -enable-objc-interop $sdk -I $out_dir -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_doc_name swiftc_flags -module-name $module_name -emit-module-path $out_module_name -emit-dependencies-path $out.d -emit-reference-dependencies-path $obj_dir/$basename.swiftdeps -o $out", tool.swiftc)
	_p(1, "description = compile $out")
	_p("")

	_p("rule swiftm")
	_p(1, "command = %s -frontend -emit-module $in $parse_as_library swiftc_flags $target -enable-objc-interop $sdk -I $out_dir -F $platform_path/Developer/Library/Frameworks -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_dir/$module_name.swiftdoc -module-name $module_name -o $out", tool.swift)
	_p(1, "description = generate module")
	_p("")

	_p("rule swiftlink")
	_p(1, "command = %s $target $sdk $swiftlink_flags -L $out_dir -o $out_dir/$module_name -F $platform_path/Developer/Library/Frameworks $in", tool.swiftc)
	_p(1, "description = linking $target")
	_p("")

	_p("rule ar")
	_p(1, "command = %s cr $ar_flags $out $in $libs %s", tool.ar, (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))
	_p(1, "description = ar $out")
	_p("")

	_p("rule link")
	_p("  command = %s $in $ld_baseflags $all_ldflags $libs -o $out", tool.ld)
	_p("  description = link $out")
	_p("")

	swift.file_rules(cfg, flags)

	local objfiles = {}
	local modfiles = {}
	local docfiles = {}

	for _, file in ipairs(cfg.files) do
		if path.issourcefile(file) then
			table.insert(objfiles, swift.objectname(cfg, file))
			table.insert(modfiles, swift.modulename(cfg, file))
			table.insert(docfiles, swift.docname(cfg, file))
		end
	end
	_p("")

	swift.linker(prj, cfg, {objfiles, modfiles, docfiles}, tool, flags)

	_p("")
end

function swift.objectname(cfg, file)
	return path.join("$obj_dir", path.getname(file)..".o")
end

function swift.modulename(cfg, file)
	return path.join("$obj_dir", path.getname(file)..".o.swiftmodule")
end

function swift.docname(cfg, file)
	return path.join("$obj_dir", path.getname(file)..".o.swiftdoc")
end

function swift.file_rules(cfg, flags)
	_p("# build files")
	local sfiles = Set(cfg.files)

	for _, file in ipairs(cfg.files) do
		if path.issourcefile(file) then
			if path.isswiftfile(file) then
				local objn = swift.objectname(cfg, file)
				local modn = swift.modulename(cfg, file)
				local docn = swift.docname(cfg, file)

				_p("build %s | %s %s: swiftc %s", objn, modn, docn, file)
				_p(1, "out_module_name = %s", modn)
				_p(1, "out_doc_name = %s", docn)
				_p(1, "files = ".. ninja.list(sfiles - {file}))
				build_flags = "swiftcflags"
			end

			_p(1, "flags    = " .. flags[build_flags])
		elseif path.isresourcefile(file) then
			-- TODO
		end
	end

	_p("")
end

function swift.linker(prj, cfg, depfiles, tool)
	local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions))
	local lddeps      = ninja.list(premake.getlinks(cfg, "siblings", "fullpath")) 
	local libs        = lddeps .. " " .. ninja.list(tool.getlinkflags(cfg))

	local function writevars()
		_p(1, "all_ldflags = " .. all_ldflags)
		_p(1, "libs        = " .. libs)
	end

	local objfiles, modfiles, docfiles = table.unpack(depfiles)

	_p("build $out_dir/$module_name.swiftmodule | $out_dir/$module_name.swiftdoc: swiftm %s | %s", table.concat(modfiles, " "), table.concat(docfiles, " "))
	_p("")
		
	local output = cfg:getoutputfilename()

	if cfg.kind == "StaticLib" then
		local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false))
		_p("build %s: ar %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps)
		_p(1, "flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false)))
	elseif cfg.kind == "SharedLib" then
		_p("build %s : swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), libs)
		writevars()
	elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then
		--_p("build %s: link %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", cfg:getoutputfilename(), table.concat(objfiles, " "), lddeps)
		--writevars()
		_p("build %s: swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps)
	else
		p.error("ninja action doesn't support this kind of target " .. cfg.kind)
	end

end