xref: /freebsd/tools/build/options/makeman.lua (revision 8378665ff9176677c2ed117756afceb601a1dca0)
1*8378665fSKyle Evans--
2*8378665fSKyle Evans-- Copyright (c) 2023 Kyle Evans <kevans@FreeBSD.org>
3*8378665fSKyle Evans--
4*8378665fSKyle Evans-- SPDX-License-Identifier: BSD-2-Clause
5*8378665fSKyle Evans--
6*8378665fSKyle Evans
7*8378665fSKyle Evanslocal libgen = require('posix.libgen')
8*8378665fSKyle Evanslocal lfs = require('lfs')
9*8378665fSKyle Evanslocal stdlib = require('posix.stdlib')
10*8378665fSKyle Evanslocal unistd = require('posix.unistd')
11*8378665fSKyle Evanslocal sys_wait = require('posix.sys.wait')
12*8378665fSKyle Evans
13*8378665fSKyle Evanslocal curdate = os.date("%B %e, %Y")
14*8378665fSKyle Evans
15*8378665fSKyle Evanslocal output_head <const> = ".\\\" DO NOT EDIT-- this file is @" .. [[generated by tools/build/options/makeman.
16*8378665fSKyle Evans.Dd ]] .. curdate .. [[
17*8378665fSKyle Evans
18*8378665fSKyle Evans.Dt SRC.CONF 5
19*8378665fSKyle Evans.Os
20*8378665fSKyle Evans.Sh NAME
21*8378665fSKyle Evans.Nm src.conf
22*8378665fSKyle Evans.Nd "source build options"
23*8378665fSKyle Evans.Sh DESCRIPTION
24*8378665fSKyle EvansThe
25*8378665fSKyle Evans.Nm
26*8378665fSKyle Evansfile contains variables that control what components will be generated during
27*8378665fSKyle Evansthe build process of the
28*8378665fSKyle Evans.Fx
29*8378665fSKyle Evanssource tree; see
30*8378665fSKyle Evans.Xr build 7 .
31*8378665fSKyle Evans.Pp
32*8378665fSKyle EvansThe
33*8378665fSKyle Evans.Nm
34*8378665fSKyle Evansfile uses the standard makefile syntax.
35*8378665fSKyle EvansHowever,
36*8378665fSKyle Evans.Nm
37*8378665fSKyle Evansshould not specify any dependencies to
38*8378665fSKyle Evans.Xr make 1 .
39*8378665fSKyle EvansInstead,
40*8378665fSKyle Evans.Nm
41*8378665fSKyle Evansis to set
42*8378665fSKyle Evans.Xr make 1
43*8378665fSKyle Evansvariables that control the aspects of how the system builds.
44*8378665fSKyle Evans.Pp
45*8378665fSKyle EvansThe default location of
46*8378665fSKyle Evans.Nm
47*8378665fSKyle Evansis
48*8378665fSKyle Evans.Pa /etc/src.conf ,
49*8378665fSKyle Evansthough an alternative location can be specified in the
50*8378665fSKyle Evans.Xr make 1
51*8378665fSKyle Evansvariable
52*8378665fSKyle Evans.Va SRCCONF .
53*8378665fSKyle EvansOverriding the location of
54*8378665fSKyle Evans.Nm
55*8378665fSKyle Evansmay be necessary if the system-wide settings are not suitable
56*8378665fSKyle Evansfor a particular build.
57*8378665fSKyle EvansFor instance, setting
58*8378665fSKyle Evans.Va SRCCONF
59*8378665fSKyle Evansto
60*8378665fSKyle Evans.Pa /dev/null
61*8378665fSKyle Evanseffectively resets all build controls to their defaults.
62*8378665fSKyle Evans.Pp
63*8378665fSKyle EvansThe only purpose of
64*8378665fSKyle Evans.Nm
65*8378665fSKyle Evansis to control the compilation of the
66*8378665fSKyle Evans.Fx
67*8378665fSKyle Evanssource code, which is usually located in
68*8378665fSKyle Evans.Pa /usr/src .
69*8378665fSKyle EvansAs a rule, the system administrator creates
70*8378665fSKyle Evans.Nm
71*8378665fSKyle Evanswhen the values of certain control variables need to be changed
72*8378665fSKyle Evansfrom their defaults.
73*8378665fSKyle Evans.Pp
74*8378665fSKyle EvansIn addition, control variables can be specified
75*8378665fSKyle Evansfor a particular build via the
76*8378665fSKyle Evans.Fl D
77*8378665fSKyle Evansoption of
78*8378665fSKyle Evans.Xr make 1
79*8378665fSKyle Evansor in its environment; see
80*8378665fSKyle Evans.Xr environ 7 .
81*8378665fSKyle Evans.Pp
82*8378665fSKyle EvansThe environment of
83*8378665fSKyle Evans.Xr make 1
84*8378665fSKyle Evansfor the build can be controlled via the
85*8378665fSKyle Evans.Va SRC_ENV_CONF
86*8378665fSKyle Evansvariable, which defaults to
87*8378665fSKyle Evans.Pa /etc/src-env.conf .
88*8378665fSKyle EvansSome examples that may only be set in this file are
89*8378665fSKyle Evans.Va WITH_DIRDEPS_BUILD ,
90*8378665fSKyle Evansand
91*8378665fSKyle Evans.Va WITH_META_MODE ,
92*8378665fSKyle Evansand
93*8378665fSKyle Evans.Va MAKEOBJDIRPREFIX
94*8378665fSKyle Evansas they are environment-only variables.
95*8378665fSKyle Evans.Pp
96*8378665fSKyle EvansThe values of
97*8378665fSKyle Evans.Va WITH_
98*8378665fSKyle Evansand
99*8378665fSKyle Evans.Va WITHOUT_
100*8378665fSKyle Evansvariables are ignored regardless of their setting;
101*8378665fSKyle Evanseven if they would be set to
102*8378665fSKyle Evans.Dq Li FALSE
103*8378665fSKyle Evansor
104*8378665fSKyle Evans.Dq Li NO .
105*8378665fSKyle EvansThe presence of an option causes
106*8378665fSKyle Evansit to be honored by
107*8378665fSKyle Evans.Xr make 1 .
108*8378665fSKyle Evans.Pp
109*8378665fSKyle EvansThis list provides a name and short description for variables
110*8378665fSKyle Evansthat can be used for source builds.
111*8378665fSKyle Evans.Bl -tag -width indent
112*8378665fSKyle Evans]]
113*8378665fSKyle Evans
114*8378665fSKyle Evanslocal output_tail <const> = [[.El
115*8378665fSKyle Evans.Sh FILES
116*8378665fSKyle Evans.Bl -tag -compact -width Pa
117*8378665fSKyle Evans.It Pa /etc/src.conf
118*8378665fSKyle Evans.It Pa /etc/src-env.conf
119*8378665fSKyle Evans.It Pa /usr/share/mk/bsd.own.mk
120*8378665fSKyle Evans.El
121*8378665fSKyle Evans.Sh SEE ALSO
122*8378665fSKyle Evans.Xr make 1 ,
123*8378665fSKyle Evans.Xr make.conf 5 ,
124*8378665fSKyle Evans.Xr build 7 ,
125*8378665fSKyle Evans.Xr ports 7
126*8378665fSKyle Evans.Sh HISTORY
127*8378665fSKyle EvansThe
128*8378665fSKyle Evans.Nm
129*8378665fSKyle Evansfile appeared in
130*8378665fSKyle Evans.Fx 7.0 .
131*8378665fSKyle Evans.Sh AUTHORS
132*8378665fSKyle EvansThis manual page was autogenerated by
133*8378665fSKyle Evans.An tools/build/options/makeman .
134*8378665fSKyle Evans]]
135*8378665fSKyle Evans
136*8378665fSKyle Evanslocal scriptdir <const> = libgen.dirname(stdlib.realpath(arg[0]))
137*8378665fSKyle Evanslocal srcdir <const> = stdlib.realpath(scriptdir .. "/../../../")
138*8378665fSKyle Evanslocal makesysdir <const> = srcdir .. "/share/mk"
139*8378665fSKyle Evans
140*8378665fSKyle Evanslocal make_envvar = os.getenv("MAKE")
141*8378665fSKyle Evanslocal make_cmd_override = {}
142*8378665fSKyle Evansif make_envvar then
143*8378665fSKyle Evans	for word in make_envvar:gmatch("[^%s]+") do
144*8378665fSKyle Evans		make_cmd_override[#make_cmd_override + 1] = word
145*8378665fSKyle Evans	end
146*8378665fSKyle Evansend
147*8378665fSKyle Evans
148*8378665fSKyle Evans-- Lifted from bsdinstall/scripts/pkgbase.in (read_all)
149*8378665fSKyle Evanslocal function read_pipe(pipe)
150*8378665fSKyle Evans	local ret = ""
151*8378665fSKyle Evans	repeat
152*8378665fSKyle Evans		local buffer = assert(unistd.read(pipe, 1024))
153*8378665fSKyle Evans		ret = ret .. buffer
154*8378665fSKyle Evans	until buffer == ""
155*8378665fSKyle Evans	return ret
156*8378665fSKyle Evansend
157*8378665fSKyle Evanslocal function run_make(args)
158*8378665fSKyle Evans	local cmd_args = {"env", "-i", "make", "-C", srcdir, "-m", makesysdir,
159*8378665fSKyle Evans	    "__MAKE_CONF=/dev/null", "SRCCONF=/dev/null"}
160*8378665fSKyle Evans
161*8378665fSKyle Evans	if #make_cmd_override > 0 then
162*8378665fSKyle Evans		cmd_args[3] = make_cmd_override[1]
163*8378665fSKyle Evans		for k = 2, #make_cmd_override do
164*8378665fSKyle Evans			local val = make_cmd_override[k]
165*8378665fSKyle Evans
166*8378665fSKyle Evans			table.insert(cmd_args, 3 + (k - 1), val)
167*8378665fSKyle Evans		end
168*8378665fSKyle Evans	end
169*8378665fSKyle Evans	for k, v in ipairs(args) do
170*8378665fSKyle Evans		cmd_args[#cmd_args + 1] = v
171*8378665fSKyle Evans	end
172*8378665fSKyle Evans
173*8378665fSKyle Evans	local r, w = assert(unistd.pipe())
174*8378665fSKyle Evans	local pid = assert(unistd.fork())
175*8378665fSKyle Evans	if pid == 0 then
176*8378665fSKyle Evans		-- Child
177*8378665fSKyle Evans		assert(unistd.close(r))
178*8378665fSKyle Evans		assert(unistd.dup2(w, 1))
179*8378665fSKyle Evans		assert(unistd.dup2(w, 2))
180*8378665fSKyle Evans		assert(unistd.execp("env", cmd_args))
181*8378665fSKyle Evans		unistd._exit()
182*8378665fSKyle Evans	end
183*8378665fSKyle Evans
184*8378665fSKyle Evans	-- Parent
185*8378665fSKyle Evans	assert(unistd.close(w))
186*8378665fSKyle Evans
187*8378665fSKyle Evans	local output = read_pipe(r)
188*8378665fSKyle Evans	assert(unistd.close(r))
189*8378665fSKyle Evans
190*8378665fSKyle Evans	local _, exit_type, exit_code = assert(sys_wait.wait(pid))
191*8378665fSKyle Evans	assert(exit_type == "exited", "make exited with wrong status")
192*8378665fSKyle Evans	assert(exit_code == 0, "make exited unsuccessfully")
193*8378665fSKyle Evans	return output
194*8378665fSKyle Evansend
195*8378665fSKyle Evans
196*8378665fSKyle Evanslocal function native_target()
197*8378665fSKyle Evans	local output = run_make({"MK_AUTO_OBJ=NO", "-V", "MACHINE",
198*8378665fSKyle Evans	    "-V", "MACHINE_ARCH"})
199*8378665fSKyle Evans
200*8378665fSKyle Evans	local arch, machine_arch
201*8378665fSKyle Evans	for x in output:gmatch("[^\n]+") do
202*8378665fSKyle Evans		if not arch then
203*8378665fSKyle Evans			arch = x
204*8378665fSKyle Evans		elseif not machine_arch then
205*8378665fSKyle Evans			machine_arch = x
206*8378665fSKyle Evans		end
207*8378665fSKyle Evans	end
208*8378665fSKyle Evans
209*8378665fSKyle Evans	return arch .. "/" .. machine_arch
210*8378665fSKyle Evansend
211*8378665fSKyle Evans
212*8378665fSKyle Evanslocal function src_targets()
213*8378665fSKyle Evans	local targets = {}
214*8378665fSKyle Evans	targets[native_target()] = true
215*8378665fSKyle Evans
216*8378665fSKyle Evans	local output = run_make({"MK_AUTO_OBJ=no", "targets"})
217*8378665fSKyle Evans	local curline = 0
218*8378665fSKyle Evans
219*8378665fSKyle Evans	for line in output:gmatch("[^\n]+") do
220*8378665fSKyle Evans		curline = curline + 1
221*8378665fSKyle Evans		if curline ~= 1 then
222*8378665fSKyle Evans			local arch = line:match("[^%s]+/[^%s]+")
223*8378665fSKyle Evans
224*8378665fSKyle Evans			-- Make sure we don't roll over our default arch
225*8378665fSKyle Evans			if arch and not targets[arch] then
226*8378665fSKyle Evans				targets[arch] = false
227*8378665fSKyle Evans			end
228*8378665fSKyle Evans		end
229*8378665fSKyle Evans	end
230*8378665fSKyle Evans
231*8378665fSKyle Evans	return targets
232*8378665fSKyle Evansend
233*8378665fSKyle Evans
234*8378665fSKyle Evanslocal function config_options(srcconf, env, take_dupes, linting)
235*8378665fSKyle Evans	srcconf = srcconf or "/dev/null"
236*8378665fSKyle Evans	env = env or {}
237*8378665fSKyle Evans
238*8378665fSKyle Evans	local option_args = {".MAKE.MODE=normal", "showconfig",
239*8378665fSKyle Evans	    "SRC_ENV_CONF=" .. srcconf}
240*8378665fSKyle Evans
241*8378665fSKyle Evans	for _, val in ipairs(env) do
242*8378665fSKyle Evans		option_args[#option_args + 1] = val
243*8378665fSKyle Evans	end
244*8378665fSKyle Evans
245*8378665fSKyle Evans	local output = run_make(option_args)
246*8378665fSKyle Evans
247*8378665fSKyle Evans	local options = {}
248*8378665fSKyle Evans	local known_dupes = {}
249*8378665fSKyle Evans
250*8378665fSKyle Evans	local function warn_on_dupe(option, val)
251*8378665fSKyle Evans		if not linting or known_dupes[option] then
252*8378665fSKyle Evans			return false
253*8378665fSKyle Evans		end
254*8378665fSKyle Evans		if not option:match("^OPT_") then
255*8378665fSKyle Evans			val = val == "yes"
256*8378665fSKyle Evans		end
257*8378665fSKyle Evans
258*8378665fSKyle Evans		known_dupes[option] = true
259*8378665fSKyle Evans		return val ~= options[val]
260*8378665fSKyle Evans	end
261*8378665fSKyle Evans
262*8378665fSKyle Evans	for opt in output:gmatch("[^\n]+") do
263*8378665fSKyle Evans		if opt:match("^MK_[%a%d_]+%s+=%s+.+") then
264*8378665fSKyle Evans			local name = opt:match("MK_[%a%d_]+")
265*8378665fSKyle Evans			local val = opt:match("= .+"):sub(3)
266*8378665fSKyle Evans
267*8378665fSKyle Evans			-- Some settings, e.g., MK_INIT_ALL_ZERO, may end up
268*8378665fSKyle Evans			-- output twice for some reason that I haven't dug into;
269*8378665fSKyle Evans			-- take the first value.  In some circumstances, though,
270*8378665fSKyle Evans			-- we do make an exception and actually want to take the
271*8378665fSKyle Evans			-- latest.
272*8378665fSKyle Evans			if take_dupes or options[name] == nil then
273*8378665fSKyle Evans				options[name] = val == "yes"
274*8378665fSKyle Evans			elseif warn_on_dupe(name, val) then
275*8378665fSKyle Evans				io.stderr:write("ignoring duplicate option " ..
276*8378665fSKyle Evans				    name .. "\n")
277*8378665fSKyle Evans			end
278*8378665fSKyle Evans		elseif opt:match("^OPT_[%a%d_]+%s+=%s+.+") then
279*8378665fSKyle Evans			local name = opt:match("OPT_[%a%d_]+")
280*8378665fSKyle Evans			local val = opt:match("= .+"):sub(3)
281*8378665fSKyle Evans
282*8378665fSKyle Evans			-- Multi-value options will arbitrarily use a table here
283*8378665fSKyle Evans			-- to indicate the difference.
284*8378665fSKyle Evans			if take_dupes or options[name] == nil then
285*8378665fSKyle Evans				options[name] = val
286*8378665fSKyle Evans			elseif warn_on_dupe(name, val) then
287*8378665fSKyle Evans				io.stderr:write("ignoring duplicate option " ..
288*8378665fSKyle Evans				    name .. "\n")
289*8378665fSKyle Evans			end
290*8378665fSKyle Evans		end
291*8378665fSKyle Evans	end
292*8378665fSKyle Evans
293*8378665fSKyle Evans	return options
294*8378665fSKyle Evansend
295*8378665fSKyle Evans
296*8378665fSKyle Evanslocal function env_only_options()
297*8378665fSKyle Evans	local output = run_make({"MK_AUTO_OBJ=no", "-V", "__ENV_ONLY_OPTIONS"})
298*8378665fSKyle Evans	local options = {}
299*8378665fSKyle Evans
300*8378665fSKyle Evans	for opt in output:gmatch("[^%s]+") do
301*8378665fSKyle Evans		options["MK_" .. opt] = true
302*8378665fSKyle Evans	end
303*8378665fSKyle Evans
304*8378665fSKyle Evans	return options
305*8378665fSKyle Evansend
306*8378665fSKyle Evans
307*8378665fSKyle Evanslocal function required_options()
308*8378665fSKyle Evans	local output = run_make({"-f", "share/mk/src.opts.mk", "-V",
309*8378665fSKyle Evans	    "__REQUIRED_OPTIONS"})
310*8378665fSKyle Evans	local options = {}
311*8378665fSKyle Evans
312*8378665fSKyle Evans	for opt in output:gmatch("[^%s]+") do
313*8378665fSKyle Evans		options["MK_" .. opt] = true
314*8378665fSKyle Evans	end
315*8378665fSKyle Evans
316*8378665fSKyle Evans	return options
317*8378665fSKyle Evansend
318*8378665fSKyle Evans
319*8378665fSKyle Evanslocal function config_description(option_name)
320*8378665fSKyle Evans	local fh = io.open(scriptdir .. "/" .. option_name)
321*8378665fSKyle Evans	local desc
322*8378665fSKyle Evans
323*8378665fSKyle Evans	if fh then
324*8378665fSKyle Evans		desc = ""
325*8378665fSKyle Evans		for line in fh:lines() do
326*8378665fSKyle Evans			if not line:match("%$FreeBSD%$") then
327*8378665fSKyle Evans				desc = desc .. line .. "\n"
328*8378665fSKyle Evans			end
329*8378665fSKyle Evans		end
330*8378665fSKyle Evans
331*8378665fSKyle Evans		assert(fh:close())
332*8378665fSKyle Evans	end
333*8378665fSKyle Evans
334*8378665fSKyle Evans	return desc
335*8378665fSKyle Evansend
336*8378665fSKyle Evans
337*8378665fSKyle Evanslocal function config_descriptions(options)
338*8378665fSKyle Evans	local desc = {}
339*8378665fSKyle Evans	for name, _ in pairs(options) do
340*8378665fSKyle Evans		if name:match("^MK_") then
341*8378665fSKyle Evans			local basename = name:gsub("^MK_", "")
342*8378665fSKyle Evans			local with_name = "WITH_" .. basename
343*8378665fSKyle Evans			local without_name = "WITHOUT_" .. basename
344*8378665fSKyle Evans
345*8378665fSKyle Evans			desc[with_name] = config_description(with_name)
346*8378665fSKyle Evans			desc[without_name] = config_description(without_name)
347*8378665fSKyle Evans		elseif name:match("^OPT_") then
348*8378665fSKyle Evans			local basename = name:gsub("^OPT_", "")
349*8378665fSKyle Evans
350*8378665fSKyle Evans			desc[name] = config_description(basename)
351*8378665fSKyle Evans		end
352*8378665fSKyle Evans	end
353*8378665fSKyle Evans	return desc
354*8378665fSKyle Evansend
355*8378665fSKyle Evans
356*8378665fSKyle Evanslocal function dependent_options(tmpdir, option_name, all_opts, omit_others)
357*8378665fSKyle Evans	local opt_sense = not not option_name:match("^WITH_")
358*8378665fSKyle Evans	local base_option_name = option_name:gsub("^[^_]+_", "")
359*8378665fSKyle Evans	local prefix = (opt_sense and "WITHOUT_") or "WITH_"
360*8378665fSKyle Evans
361*8378665fSKyle Evans	local srcconf = tmpdir .. "/src-" ..prefix .. "ALL_" ..
362*8378665fSKyle Evans	    option_name .. ".conf"
363*8378665fSKyle Evans	local fh = assert(io.open(srcconf, "w+"))
364*8378665fSKyle Evans
365*8378665fSKyle Evans	fh:write(option_name .. "=\"YES\"\n")
366*8378665fSKyle Evans	if not omit_others then
367*8378665fSKyle Evans		for opt, value in pairs(all_opts) do
368*8378665fSKyle Evans			local base_opt = opt:gsub("^MK_", "")
369*8378665fSKyle Evans
370*8378665fSKyle Evans			if base_opt ~= base_option_name then
371*8378665fSKyle Evans				local opt_prefix = (value and "WITH_") or "WITHOUT_"
372*8378665fSKyle Evans				fh:write(opt_prefix .. base_opt .. "=\"YES\"\n")
373*8378665fSKyle Evans			end
374*8378665fSKyle Evans		end
375*8378665fSKyle Evans	end
376*8378665fSKyle Evans	assert(fh:close())
377*8378665fSKyle Evans
378*8378665fSKyle Evans	local option_name_key = "MK_" .. base_option_name
379*8378665fSKyle Evans	local options = config_options(srcconf, nil, omit_others)
380*8378665fSKyle Evans	for name, value in pairs(options) do
381*8378665fSKyle Evans		if name == option_name_key or value == all_opts[name] then
382*8378665fSKyle Evans			options[name] = nil
383*8378665fSKyle Evans		elseif name:match("^OPT_") then
384*8378665fSKyle Evans			-- Strip out multi-option values at the moment, they do
385*8378665fSKyle Evans			-- not really make sense.
386*8378665fSKyle Evans			options[name] = nil
387*8378665fSKyle Evans		end
388*8378665fSKyle Evans	end
389*8378665fSKyle Evans
390*8378665fSKyle Evans	return options
391*8378665fSKyle Evansend
392*8378665fSKyle Evans
393*8378665fSKyle Evanslocal function export_option_table(fd, name, options)
394*8378665fSKyle Evans	unistd.write(fd, name .. " = {")
395*8378665fSKyle Evans	for k, v in pairs(options) do
396*8378665fSKyle Evans		v = (v and "true") or "false"
397*8378665fSKyle Evans		unistd.write(fd, "['" .. k .. "'] = " .. v .. ",")
398*8378665fSKyle Evans	end
399*8378665fSKyle Evans	unistd.write(fd, "}")
400*8378665fSKyle Evansend
401*8378665fSKyle Evans
402*8378665fSKyle Evanslocal function all_dependent_options(tmpdir, options, default_opts,
403*8378665fSKyle Evans    with_all_opts, without_all_opts)
404*8378665fSKyle Evans	local all_enforced_options = {}
405*8378665fSKyle Evans	local all_effect_options = {}
406*8378665fSKyle Evans	local children = {}
407*8378665fSKyle Evans
408*8378665fSKyle Evans	for _, name in ipairs(options) do
409*8378665fSKyle Evans		local rfd, wfd = assert(unistd.pipe())
410*8378665fSKyle Evans		local pid = assert(unistd.fork())
411*8378665fSKyle Evans
412*8378665fSKyle Evans		if pid == 0 then
413*8378665fSKyle Evans			-- We need to pcall() this so that errors bubble up to
414*8378665fSKyle Evans			-- our _exit() call rather than the main exit.
415*8378665fSKyle Evans			local ret, errobj = pcall(function()
416*8378665fSKyle Evans				unistd.close(rfd)
417*8378665fSKyle Evans
418*8378665fSKyle Evans				local compare_table
419*8378665fSKyle Evans				if name:match("^WITHOUT") then
420*8378665fSKyle Evans					compare_table = with_all_opts
421*8378665fSKyle Evans				else
422*8378665fSKyle Evans					compare_table = without_all_opts
423*8378665fSKyle Evans				end
424*8378665fSKyle Evans
425*8378665fSKyle Evans				-- List of knobs forced on by this one
426*8378665fSKyle Evans				local enforced_options = dependent_options(tmpdir, name,
427*8378665fSKyle Evans				    compare_table)
428*8378665fSKyle Evans				-- List of knobs implied by this by one (once additionally
429*8378665fSKyle Evans				-- filtered based on enforced_options values)
430*8378665fSKyle Evans				local effect_options = dependent_options(tmpdir, name,
431*8378665fSKyle Evans				    default_opts, true)
432*8378665fSKyle Evans
433*8378665fSKyle Evans				export_option_table(wfd, "enforced_options",
434*8378665fSKyle Evans				    enforced_options)
435*8378665fSKyle Evans				export_option_table(wfd, "effect_options",
436*8378665fSKyle Evans				    effect_options)
437*8378665fSKyle Evans			end)
438*8378665fSKyle Evans
439*8378665fSKyle Evans			io.stderr:write(".")
440*8378665fSKyle Evans
441*8378665fSKyle Evans			if ret then
442*8378665fSKyle Evans				unistd._exit(0)
443*8378665fSKyle Evans			else
444*8378665fSKyle Evans				unistd.write(wfd, errobj)
445*8378665fSKyle Evans				unistd._exit(1)
446*8378665fSKyle Evans			end
447*8378665fSKyle Evans		end
448*8378665fSKyle Evans
449*8378665fSKyle Evans		unistd.close(wfd)
450*8378665fSKyle Evans		children[pid] = {name, rfd}
451*8378665fSKyle Evans	end
452*8378665fSKyle Evans
453*8378665fSKyle Evans	while next(children) ~= nil do
454*8378665fSKyle Evans::again::
455*8378665fSKyle Evans		local pid, status, exitcode = sys_wait.wait(-1)
456*8378665fSKyle Evans
457*8378665fSKyle Evans		if status ~= "exited" then
458*8378665fSKyle Evans			goto again
459*8378665fSKyle Evans		end
460*8378665fSKyle Evans
461*8378665fSKyle Evans		local info = children[pid]
462*8378665fSKyle Evans		children[pid] = nil
463*8378665fSKyle Evans
464*8378665fSKyle Evans		local name = info[1]
465*8378665fSKyle Evans		local rfd = info[2]
466*8378665fSKyle Evans		local buf = ''
467*8378665fSKyle Evans		local rbuf, sz
468*8378665fSKyle Evans
469*8378665fSKyle Evans		-- Drain the pipe
470*8378665fSKyle Evans		rbuf = unistd.read(rfd, 512)
471*8378665fSKyle Evans		while #rbuf ~= 0 do
472*8378665fSKyle Evans			buf = buf .. rbuf
473*8378665fSKyle Evans			rbuf = unistd.read(rfd, 512)
474*8378665fSKyle Evans		end
475*8378665fSKyle Evans
476*8378665fSKyle Evans		unistd.close(rfd)
477*8378665fSKyle Evans
478*8378665fSKyle Evans		if exitcode ~= 0 then
479*8378665fSKyle Evans			error("Child " .. pid .. " failed, buf: " .. buf)
480*8378665fSKyle Evans		end
481*8378665fSKyle Evans
482*8378665fSKyle Evans		-- The child has written a pair of tables named enforced_options
483*8378665fSKyle Evans		-- and effect_options to the pipe.  We'll load the pipe buffer
484*8378665fSKyle Evans		-- as a string and then yank these out of the clean environment
485*8378665fSKyle Evans		-- that we execute the chunk in.
486*8378665fSKyle Evans		local child_env = {}
487*8378665fSKyle Evans		local res, err = pcall(load(buf, "child", "t", child_env))
488*8378665fSKyle Evans
489*8378665fSKyle Evans		all_enforced_options[name] = child_env["enforced_options"]
490*8378665fSKyle Evans		all_effect_options[name] = child_env["effect_options"]
491*8378665fSKyle Evans	end
492*8378665fSKyle Evans
493*8378665fSKyle Evans	io.stderr:write("\n")
494*8378665fSKyle Evans	return all_enforced_options, all_effect_options
495*8378665fSKyle Evansend
496*8378665fSKyle Evans
497*8378665fSKyle Evanslocal function get_defaults(target_archs, native_default_opts)
498*8378665fSKyle Evans	local target_defaults = {}
499*8378665fSKyle Evans	-- Set of options with differing defaults in some archs
500*8378665fSKyle Evans	local different_defaults = {}
501*8378665fSKyle Evans
502*8378665fSKyle Evans	for tgt, dflt in pairs(target_archs) do
503*8378665fSKyle Evans		if dflt then
504*8378665fSKyle Evans			local native_copy = {}
505*8378665fSKyle Evans			for opt, val in pairs(native_default_opts) do
506*8378665fSKyle Evans				native_copy[opt] = val
507*8378665fSKyle Evans			end
508*8378665fSKyle Evans			target_defaults[tgt] = native_copy
509*8378665fSKyle Evans			goto skip
510*8378665fSKyle Evans		end
511*8378665fSKyle Evans
512*8378665fSKyle Evans		local target = tgt:gsub("/.+$", "")
513*8378665fSKyle Evans		local target_arch = tgt:gsub("^.+/", "")
514*8378665fSKyle Evans
515*8378665fSKyle Evans		local target_opts = config_options(nil, {"TARGET=" .. target,
516*8378665fSKyle Evans		    "TARGET_ARCH=" .. target_arch})
517*8378665fSKyle Evans
518*8378665fSKyle Evans		for opt, val in pairs(target_opts) do
519*8378665fSKyle Evans			if val ~= native_default_opts[opt] then
520*8378665fSKyle Evans				different_defaults[opt] = true
521*8378665fSKyle Evans			end
522*8378665fSKyle Evans		end
523*8378665fSKyle Evans
524*8378665fSKyle Evans		target_defaults[tgt] = target_opts
525*8378665fSKyle Evans::skip::
526*8378665fSKyle Evans	end
527*8378665fSKyle Evans
528*8378665fSKyle Evans	for opt in pairs(native_default_opts) do
529*8378665fSKyle Evans		if different_defaults[opt] == nil then
530*8378665fSKyle Evans			for _, opts in pairs(target_defaults) do
531*8378665fSKyle Evans				opts[opt] = nil
532*8378665fSKyle Evans			end
533*8378665fSKyle Evans		end
534*8378665fSKyle Evans	end
535*8378665fSKyle Evans
536*8378665fSKyle Evans	for tgt, opts in pairs(target_defaults) do
537*8378665fSKyle Evans		local val = opts["MK_ACPI"]
538*8378665fSKyle Evans
539*8378665fSKyle Evans		if val ~= nil then
540*8378665fSKyle Evans			print(" - " .. tgt .. ": " .. ((val and "yes") or "no"))
541*8378665fSKyle Evans		end
542*8378665fSKyle Evans	end
543*8378665fSKyle Evans
544*8378665fSKyle Evans	return target_defaults, different_defaults
545*8378665fSKyle Evansend
546*8378665fSKyle Evans
547*8378665fSKyle Evanslocal function option_comparator(lhs, rhs)
548*8378665fSKyle Evans	-- Convert both options to the base name, compare that instead unless
549*8378665fSKyle Evans	-- they're the same option.  For the same option, we just want to get
550*8378665fSKyle Evans	-- ordering between WITH_/WITHOUT_ correct.
551*8378665fSKyle Evans	local base_lhs = lhs:gsub("^[^_]+_", "")
552*8378665fSKyle Evans	local base_rhs = rhs:gsub("^[^_]+_", "")
553*8378665fSKyle Evans
554*8378665fSKyle Evans	if base_lhs == base_rhs then
555*8378665fSKyle Evans		return lhs < rhs
556*8378665fSKyle Evans	else
557*8378665fSKyle Evans		return base_lhs < base_rhs
558*8378665fSKyle Evans	end
559*8378665fSKyle Evansend
560*8378665fSKyle Evans
561*8378665fSKyle Evanslocal function main(tmpdir)
562*8378665fSKyle Evans	io.stderr:write("building src.conf.5 man page from files in " ..
563*8378665fSKyle Evans	    scriptdir .. "\n")
564*8378665fSKyle Evans
565*8378665fSKyle Evans	local env_only_opts <const> = env_only_options()
566*8378665fSKyle Evans	local default_opts = config_options(nil, nil, nil, true)
567*8378665fSKyle Evans	local opt_descriptions = config_descriptions(default_opts)
568*8378665fSKyle Evans	local srcconf_all <const> = tmpdir .. "/src-all-enabled.conf"
569*8378665fSKyle Evans	local fh = io.open(srcconf_all, "w+")
570*8378665fSKyle Evans	local all_targets = src_targets()
571*8378665fSKyle Evans	local target_defaults, different_defaults = get_defaults(all_targets,
572*8378665fSKyle Evans	    default_opts)
573*8378665fSKyle Evans	local options = {}
574*8378665fSKyle Evans	local without_all_opts = {}
575*8378665fSKyle Evans
576*8378665fSKyle Evans	for name, value in pairs(default_opts) do
577*8378665fSKyle Evans		if name:match("^MK_") then
578*8378665fSKyle Evans			local base_name = name:gsub("^MK_", "")
579*8378665fSKyle Evans			local with_name = "WITH_" .. base_name
580*8378665fSKyle Evans			local without_name = "WITHOUT_" .. base_name
581*8378665fSKyle Evans			-- If it's differently defaulted on some architectures,
582*8378665fSKyle Evans			-- we'll split it into WITH_/WITHOUT_ just to simplify
583*8378665fSKyle Evans			-- some later bits.
584*8378665fSKyle Evans			if different_defaults[name] ~= nil then
585*8378665fSKyle Evans				options[#options + 1] = with_name
586*8378665fSKyle Evans				options[#options + 1] = without_name
587*8378665fSKyle Evans			elseif value then
588*8378665fSKyle Evans				options[#options + 1] = without_name
589*8378665fSKyle Evans			else
590*8378665fSKyle Evans				options[#options + 1] = with_name
591*8378665fSKyle Evans			end
592*8378665fSKyle Evans
593*8378665fSKyle Evans			without_all_opts[name] = false
594*8378665fSKyle Evans			assert(fh:write(with_name .. '="YES"\n'))
595*8378665fSKyle Evans		else
596*8378665fSKyle Evans			options[#options + 1] = name
597*8378665fSKyle Evans		end
598*8378665fSKyle Evans	end
599*8378665fSKyle Evans
600*8378665fSKyle Evans	assert(fh:close())
601*8378665fSKyle Evans
602*8378665fSKyle Evans	local with_all_opts = config_options(srcconf_all)
603*8378665fSKyle Evans	local all_enforced_options, all_effect_options
604*8378665fSKyle Evans	local all_required_options = required_options()
605*8378665fSKyle Evans
606*8378665fSKyle Evans	all_enforced_options, all_effect_options = all_dependent_options(tmpdir,
607*8378665fSKyle Evans	    options, default_opts, with_all_opts, without_all_opts)
608*8378665fSKyle Evans
609*8378665fSKyle Evans	table.sort(options, option_comparator)
610*8378665fSKyle Evans	io.stdout:write(output_head)
611*8378665fSKyle Evans	for _, name in ipairs(options) do
612*8378665fSKyle Evans		local value
613*8378665fSKyle Evans
614*8378665fSKyle Evans		if name:match("^OPT_") then
615*8378665fSKyle Evans			goto skip
616*8378665fSKyle Evans		end
617*8378665fSKyle Evans		assert(name:match("^WITH"), "Name looks wrong: " .. name)
618*8378665fSKyle Evans		local describe_option = name
619*8378665fSKyle Evans
620*8378665fSKyle Evans		value = not not name:match("^WITHOUT")
621*8378665fSKyle Evans
622*8378665fSKyle Evans		-- Normalize name to MK_ for indexing into various other
623*8378665fSKyle Evans		-- arrays
624*8378665fSKyle Evans		name = "MK_" .. name:gsub("^[^_]+_", "")
625*8378665fSKyle Evans
626*8378665fSKyle Evans		print(".It Va " .. describe_option:gsub("^OPT_", ""))
627*8378665fSKyle Evans		if opt_descriptions[describe_option] then
628*8378665fSKyle Evans			io.stdout:write(opt_descriptions[describe_option])
629*8378665fSKyle Evans		else
630*8378665fSKyle Evans			io.stderr:write("Missing description for " ..
631*8378665fSKyle Evans			    describe_option .. "\n")
632*8378665fSKyle Evans		end
633*8378665fSKyle Evans
634*8378665fSKyle Evans		local enforced_options = all_enforced_options[describe_option]
635*8378665fSKyle Evans		local effect_options = all_effect_options[describe_option]
636*8378665fSKyle Evans
637*8378665fSKyle Evans		if different_defaults[name] ~= nil then
638*8378665fSKyle Evans			print([[.Pp
639*8378665fSKyle EvansThis is a default setting on]])
640*8378665fSKyle Evans
641*8378665fSKyle Evans			local which_targets = {}
642*8378665fSKyle Evans			for tgt, tgt_options in pairs(target_defaults) do
643*8378665fSKyle Evans				if tgt_options[name] ~= value then
644*8378665fSKyle Evans					which_targets[#which_targets + 1] = tgt
645*8378665fSKyle Evans				end
646*8378665fSKyle Evans			end
647*8378665fSKyle Evans
648*8378665fSKyle Evans			table.sort(which_targets)
649*8378665fSKyle Evans			for idx, tgt in ipairs(which_targets) do
650*8378665fSKyle Evans				io.stdout:write(tgt)
651*8378665fSKyle Evans				if idx < #which_targets - 1 then
652*8378665fSKyle Evans					io.stdout:write(", ")
653*8378665fSKyle Evans				elseif idx == #which_targets - 1 then
654*8378665fSKyle Evans					io.stdout:write(" and ")
655*8378665fSKyle Evans				end
656*8378665fSKyle Evans			end
657*8378665fSKyle Evans			print(".")
658*8378665fSKyle Evans		end
659*8378665fSKyle Evans
660*8378665fSKyle Evans		-- Unset any implied options that are actually required.
661*8378665fSKyle Evans		for dep_opt in pairs(enforced_options) do
662*8378665fSKyle Evans			if all_required_options[dep_opt] then
663*8378665fSKyle Evans				enforced_options[dep_opt] = nil
664*8378665fSKyle Evans			end
665*8378665fSKyle Evans		end
666*8378665fSKyle Evans		if next(enforced_options) ~= nil then
667*8378665fSKyle Evans			print([[When set, it enforces these options:
668*8378665fSKyle Evans.Pp
669*8378665fSKyle Evans.Bl -item -compact]])
670*8378665fSKyle Evans
671*8378665fSKyle Evans			local sorted_dep_opt = {}
672*8378665fSKyle Evans			for dep_opt in pairs(enforced_options) do
673*8378665fSKyle Evans				sorted_dep_opt[#sorted_dep_opt + 1] = dep_opt
674*8378665fSKyle Evans			end
675*8378665fSKyle Evans
676*8378665fSKyle Evans			table.sort(sorted_dep_opt)
677*8378665fSKyle Evans			for _, dep_opt in ipairs(sorted_dep_opt) do
678*8378665fSKyle Evans				local dep_val = enforced_options[dep_opt]
679*8378665fSKyle Evans				local dep_prefix = (dep_val and "WITH_") or
680*8378665fSKyle Evans				    "WITHOUT_"
681*8378665fSKyle Evans				local dep_name = dep_opt:gsub("^MK_",
682*8378665fSKyle Evans				    dep_prefix)
683*8378665fSKyle Evans				print(".It")
684*8378665fSKyle Evans				print(".Va " .. dep_name)
685*8378665fSKyle Evans			end
686*8378665fSKyle Evans
687*8378665fSKyle Evans			print(".El")
688*8378665fSKyle Evans		end
689*8378665fSKyle Evans
690*8378665fSKyle Evans		if next(effect_options) ~= nil then
691*8378665fSKyle Evans			if next(enforced_options) ~= nil then
692*8378665fSKyle Evans				-- Remove any options that were previously
693*8378665fSKyle Evans				-- noted as enforced...
694*8378665fSKyle Evans				for opt, val in pairs(effect_options) do
695*8378665fSKyle Evans					if enforced_options[opt] == val then
696*8378665fSKyle Evans						effect_options[opt] = nil
697*8378665fSKyle Evans					end
698*8378665fSKyle Evans				end
699*8378665fSKyle Evans
700*8378665fSKyle Evans				-- ... and this could leave us with an empty
701*8378665fSKyle Evans				-- set.
702*8378665fSKyle Evans				if next(effect_options) == nil then
703*8378665fSKyle Evans					goto noenforce
704*8378665fSKyle Evans				end
705*8378665fSKyle Evans
706*8378665fSKyle Evans				print(".Pp")
707*8378665fSKyle Evans			end
708*8378665fSKyle Evans
709*8378665fSKyle Evans			print([[When set, these options are also in effect:
710*8378665fSKyle Evans.Pp
711*8378665fSKyle Evans.Bl -inset -compact]])
712*8378665fSKyle Evans
713*8378665fSKyle Evans			local sorted_dep_opt = {}
714*8378665fSKyle Evans			for dep_opt in pairs(effect_options) do
715*8378665fSKyle Evans				sorted_dep_opt[#sorted_dep_opt + 1] = dep_opt
716*8378665fSKyle Evans			end
717*8378665fSKyle Evans
718*8378665fSKyle Evans			table.sort(sorted_dep_opt)
719*8378665fSKyle Evans			for _, dep_opt in ipairs(sorted_dep_opt) do
720*8378665fSKyle Evans				local dep_val = effect_options[dep_opt]
721*8378665fSKyle Evans				local dep_prefix = (dep_val and "WITH_") or
722*8378665fSKyle Evans				    "WITHOUT_"
723*8378665fSKyle Evans				local not_dep_prefix = ((not dep_val) and "WITH_") or
724*8378665fSKyle Evans				    "WITHOUT_"
725*8378665fSKyle Evans				local dep_name = dep_opt:gsub("^MK_",
726*8378665fSKyle Evans				    dep_prefix)
727*8378665fSKyle Evans				local not_dep_name = dep_opt:gsub("^MK_",
728*8378665fSKyle Evans				    not_dep_prefix)
729*8378665fSKyle Evans
730*8378665fSKyle Evans				print(".It Va " .. dep_name)
731*8378665fSKyle Evans				print("(unless")
732*8378665fSKyle Evans				print(".Va " .. not_dep_name)
733*8378665fSKyle Evans				print("is set explicitly)")
734*8378665fSKyle Evans			end
735*8378665fSKyle Evans
736*8378665fSKyle Evans			print(".El")
737*8378665fSKyle Evans::noenforce::
738*8378665fSKyle Evans		end
739*8378665fSKyle Evans
740*8378665fSKyle Evans		if env_only_opts[name] ~= nil then
741*8378665fSKyle Evans			print([[.Pp
742*8378665fSKyle EvansThis must be set in the environment, make command line, or
743*8378665fSKyle Evans.Pa /etc/src-env.conf ,
744*8378665fSKyle Evansnot
745*8378665fSKyle Evans.Pa /etc/src.conf .]])
746*8378665fSKyle Evans		end
747*8378665fSKyle Evans		::skip::
748*8378665fSKyle Evans	end
749*8378665fSKyle Evans	print([[.El
750*8378665fSKyle Evans.Pp
751*8378665fSKyle EvansThe following options accept a single value from a list of valid values.
752*8378665fSKyle Evans.Bl -tag -width indent]])
753*8378665fSKyle Evans	for _, name in ipairs(options) do
754*8378665fSKyle Evans		if name:match("^OPT_") then
755*8378665fSKyle Evans			local desc = opt_descriptions[name]
756*8378665fSKyle Evans
757*8378665fSKyle Evans			print(".It Va " .. name:gsub("^OPT_", ""))
758*8378665fSKyle Evans			if desc then
759*8378665fSKyle Evans				io.stdout:write(desc)
760*8378665fSKyle Evans			else
761*8378665fSKyle Evans				io.stderr:write("Missing description for " ..
762*8378665fSKyle Evans				    name .. "\n")
763*8378665fSKyle Evans			end
764*8378665fSKyle Evans		end
765*8378665fSKyle Evans	end
766*8378665fSKyle Evans	io.stdout:write(output_tail)
767*8378665fSKyle Evansend
768*8378665fSKyle Evans
769*8378665fSKyle Evanslocal tmpdir = "/tmp/makeman." .. unistd.getpid()
770*8378665fSKyle Evans
771*8378665fSKyle Evansif not lfs.mkdir(tmpdir) then
772*8378665fSKyle Evans	error("Failed to create tempdir " .. tmpdir)
773*8378665fSKyle Evansend
774*8378665fSKyle Evans
775*8378665fSKyle Evans-- Catch any errors so that we can properly clean up, then re-throw it.
776*8378665fSKyle Evanslocal ret, errobj = pcall(main, tmpdir)
777*8378665fSKyle Evans
778*8378665fSKyle Evansfor fname in lfs.dir(tmpdir) do
779*8378665fSKyle Evans	if fname ~= "." and fname ~= ".." then
780*8378665fSKyle Evans		assert(os.remove(tmpdir .. "/" .. fname))
781*8378665fSKyle Evans	end
782*8378665fSKyle Evansend
783*8378665fSKyle Evans
784*8378665fSKyle Evansif not lfs.rmdir(tmpdir) then
785*8378665fSKyle Evans	assert(io.stderr:write("Failed to clean up tmpdir: " .. tmpdir .. "\n"))
786*8378665fSKyle Evansend
787*8378665fSKyle Evans
788*8378665fSKyle Evansif not ret then
789*8378665fSKyle Evans	io.stderr:write(errobj .. "\n")
790*8378665fSKyle Evans	os.exit(1)
791*8378665fSKyle Evansend
792