1import sys
2import os
3import shutil
4import multiprocessing
5import SCons.Util
6
7## Configuration
8
9opts = Variables('Local.sc')
10
11opts.AddVariables(
12    ("CC", "C Compiler"),
13    ("AS", "Assembler"),
14    ("LINK", "Linker"),
15    ("AR", "Archiver"),
16    ("RANLIB", "Archiver Indexer"),
17    ("BUILDTYPE", "Build type (RELEASE, DEBUG, or PERF)", "RELEASE"),
18    ("VERBOSE", "Show full build information (0 or 1)", "0"),
19    ("STRICT", "Strict error checking (0 or 1)", "0"),
20    ("NUMCPUS", "Number of CPUs to use for build (0 means auto).", "0"),
21    ("WITH_GPROF", "Include gprof profiling (0 or 1).", "0"),
22    ("PREFIX", "Installation target directory.", "#pxelinux"),
23    ("ARCH", "Target Architecture", "amd64"),
24    ("BOOTDISK", "Build boot disk (0 or 1)", "1"),
25    ("BOOTDISK_SIZE", "Boot disk size", "128")
26)
27
28env = Environment(options = opts,
29                  tools = ['default', 'compilation_db'],
30                  ENV = os.environ)
31Help(opts.GenerateHelpText(env))
32
33# Copy environment variables
34if 'CC' in os.environ:
35    env["CC"] = os.getenv('CC')
36if 'AS' in os.environ:
37    env["AS"] = os.getenv('AS')
38if 'LD' in os.environ:
39    env["LINK"] = os.getenv('LD')
40if 'AR' in os.environ:
41    env["AR"] = os.getenv('AR')
42if 'RANLIB' in os.environ:
43    env["RANLIB"] = os.getenv('RANLIB')
44if 'CFLAGS' in os.environ:
45    env.Append(CCFLAGS = SCons.Util.CLVar(os.environ['CFLAGS']))
46if 'CPPFLAGS' in os.environ:
47    env.Append(CPPFLAGS = SCons.Util.CLVar(os.environ['CPPFLAGS']))
48if 'LDFLAGS' in os.environ:
49    env.Append(LINKFLAGS = SCons.Util.CLVar(os.environ['LDFLAGS']))
50
51toolenv = env.Clone()
52
53env.Append(CFLAGS = [ "-Wshadow", "-Wno-typedef-redefinition" ])
54env.Append(CPPFLAGS = [ "-target", "x86_64-freebsd-freebsd-elf",
55                        "-fno-builtin", "-fno-stack-protector",
56                        "-fno-optimize-sibling-calls" ])
57env.Append(LINKFLAGS = [ "-no-pie" ])
58
59if (env["STRICT"] == "1"):
60    env.Append(CPPFLAGS = [ "-Wformat=2", "-Wmissing-format-attribute",
61                            "-Wthread-safety", "-Wwrite-strings" ])
62
63if env["WITH_GPROF"] == "1":
64    env.Append(CPPFLAGS = [ "-pg" ])
65    env.Append(LINKFLAGS = [ "-pg" ])
66
67env.Append(CPPFLAGS = "-DBUILDTYPE=" + env["BUILDTYPE"])
68if env["BUILDTYPE"] == "DEBUG":
69    env.Append(CPPFLAGS = [ "-g", "-DDEBUG", "-Wall",
70        "-Wno-deprecated-declarations" ])
71    env.Append(LINKFLAGS = [ "-g" ])
72elif env["BUILDTYPE"] == "PERF":
73    env.Append(CPPFLAGS = [ "-g", "-DNDEBUG", "-Wall", "-O2"])
74    env.Append(LDFLAGS = [ "-g" ])
75elif env["BUILDTYPE"] == "RELEASE":
76    env.Append(CPPFLAGS = ["-DNDEBUG", "-Wall", "-O2"])
77else:
78    print("Error BUILDTYPE must be RELEASE or DEBUG")
79    sys.exit(-1)
80
81if env["ARCH"] != "amd64":
82    print("Unsupported architecture: " + env["ARCH"])
83    sys.exit(-1)
84
85try:
86    hf = open(".git/HEAD", 'r')
87    head = hf.read()
88    if head.startswith("ref: "):
89        if head.endswith("\n"):
90            head = head[0:-1]
91        with open(".git/" + head[5:]) as bf:
92            branch = bf.read()
93            if branch.endswith("\n"):
94                branch = branch[0:-1]
95            env.Append(CPPFLAGS = [ "-DGIT_VERSION=\\\"" + branch + "\\\""])
96except IOError:
97    pass
98
99if env["VERBOSE"] == "0":
100    env["CCCOMSTR"] = "Compiling $SOURCE"
101    env["SHCCCOMSTR"] = "Compiling $SOURCE"
102    env["ARCOMSTR"] = "Creating library $TARGET"
103    env["RANLIBCOMSTR"] = "Indexing library $TARGET"
104    env["LINKCOMSTR"] = "Linking $TARGET"
105    env["ASCOMSTR"] = "Assembling $TARGET"
106    env["ASPPCOMSTR"] = "Assembling $TARGET"
107    env["ARCOMSTR"] = "Archiving $TARGET"
108    env["RANLIBCOMSTR"] = "Indexing $TARGET"
109
110def GetNumCPUs(env):
111    if env["NUMCPUS"] != "0":
112        return int(env["NUMCPUS"])
113    return 2*multiprocessing.cpu_count()
114
115env.SetOption('num_jobs', GetNumCPUs(env))
116
117def CopyTree(dst, src, env):
118    def DirCopyHelper(src, dst):
119        for f in os.listdir(src):
120            srcPath = os.path.join(src, f)
121            dstPath = os.path.join(dst, f)
122            if f.startswith("."):
123                # Ignore hidden files
124                pass
125            elif os.path.isdir(srcPath):
126                if not os.path.exists(dstPath):
127                    os.makedirs(dstPath)
128                DirCopyHelper(srcPath, dstPath)
129            else:
130                env.Command(dstPath, srcPath, Copy("$TARGET", "$SOURCE"))
131            if (not os.path.exists(dst)):
132                os.makedirs(dst)
133    DirCopyHelper(src, dst)
134
135# XXX: Hack to support clang static analyzer
136def CheckFailed():
137    if os.getenv('CCC_ANALYZER_OUTPUT_FORMAT') != None:
138        return
139    Exit(1)
140
141# Configuration
142conf = env.Configure()
143
144if not conf.CheckCC():
145    print('Your C compiler and/or environment is incorrectly configured.')
146    CheckFailed()
147
148if not env["CCVERSION"].startswith("15."):
149    print('Only Clang 15 is supported')
150    print('You are running: ' + env["CCVERSION"])
151    CheckFailed()
152
153conf.Finish()
154
155Export('env')
156Export('toolenv')
157
158
159# Program start/end
160env["CRTBEGIN"] = [ "#build/lib/libc/crti.o", "#build/lib/libc/crt1.o" ]
161env["CRTEND"] = [ "#build/lib/libc/crtn.o" ]
162
163# Debugging Tools
164
165# Create include tree
166CopyTree('build/include', 'include', env)
167CopyTree('build/include/sys', 'sys/include', env)
168CopyTree('build/include/machine', 'sys/' + env['ARCH'] + '/include', env)
169#CopyTree('build/include/', 'lib/liblwip/src/include', env)
170
171# Build Targets
172SConscript('sys/SConscript', variant_dir='build/sys')
173SConscript('lib/libc/SConscript', variant_dir='build/lib/libc')
174#SConscript('lib/liblwip/SConscript', variant_dir='build/lib/liblwip')
175SConscript('bin/cat/SConscript', variant_dir='build/bin/cat')
176SConscript('bin/date/SConscript', variant_dir='build/bin/date')
177SConscript('bin/echo/SConscript', variant_dir='build/bin/echo')
178SConscript('bin/ethdump/SConscript', variant_dir='build/bin/ethdump')
179SConscript('bin/ethinject/SConscript', variant_dir='build/bin/ethinject')
180SConscript('bin/false/SConscript', variant_dir='build/bin/false')
181SConscript('bin/ls/SConscript', variant_dir='build/bin/ls')
182SConscript('bin/shell/SConscript', variant_dir='build/bin/shell')
183SConscript('bin/stat/SConscript', variant_dir='build/bin/stat')
184SConscript('bin/true/SConscript', variant_dir='build/bin/true')
185SConscript('sbin/ifconfig/SConscript', variant_dir='build/sbin/ifconfig')
186SConscript('sbin/init/SConscript', variant_dir='build/sbin/init')
187SConscript('sbin/sysctl/SConscript', variant_dir='build/sbin/sysctl')
188SConscript('tests/SConscript', variant_dir='build/tests')
189
190# Build Tools
191env["TOOLCHAINBUILD"] = "TRUE"
192env["CC"] = "cc"
193env["LINK"] = "cc"
194SConscript('sbin/newfs_o2fs/SConscript', variant_dir='build/tools/newfs_o2fs')
195
196env.CompilationDatabase()
197
198# Install Targets
199env.Install('$PREFIX/','build/sys/castor')
200env.Alias('install','$PREFIX')
201
202# Boot Disk Target
203if env["BOOTDISK"] == "1":
204    newfs = Builder(action = 'build/tools/newfs_o2fs/newfs_o2fs -s $BOOTDISK_SIZE -m $SOURCE $TARGET')
205    env.Append(BUILDERS = {'BuildImage' : newfs})
206    bootdisk = env.BuildImage('#build/bootdisk.img', '#release/bootdisk.manifest')
207    Depends(bootdisk, "#build/tools/newfs_o2fs/newfs_o2fs")
208    Depends(bootdisk, "#build/bin/cat/cat")
209    Depends(bootdisk, "#build/bin/date/date")
210    Depends(bootdisk, "#build/bin/echo/echo")
211    Depends(bootdisk, "#build/bin/ethdump/ethdump")
212    Depends(bootdisk, "#build/bin/ethinject/ethinject")
213    Depends(bootdisk, "#build/bin/false/false")
214    Depends(bootdisk, "#build/bin/ls/ls")
215    Depends(bootdisk, "#build/bin/shell/shell")
216    Depends(bootdisk, "#build/bin/stat/stat")
217    Depends(bootdisk, "#build/bin/true/true")
218    Depends(bootdisk, "#build/sbin/ifconfig/ifconfig")
219    Depends(bootdisk, "#build/sbin/init/init")
220    Depends(bootdisk, "#build/sbin/sysctl/sysctl")
221    Depends(bootdisk, "#build/sys/castor")
222    #Depends(bootdisk, "#build/tests/lwiptest")
223    Depends(bootdisk, "#build/tests/writetest")
224    Depends(bootdisk, "#build/tests/fiotest")
225    Depends(bootdisk, "#build/tests/pthreadtest")
226    Depends(bootdisk, "#build/tests/spawnanytest")
227    Depends(bootdisk, "#build/tests/spawnmultipletest")
228    Depends(bootdisk, "#build/tests/spawnsingletest")
229    Depends(bootdisk, "#build/tests/threadtest")
230    env.Alias('bootdisk', '#build/bootdisk.img')
231    env.Install('$PREFIX/','#build/bootdisk.img')
232
233