diff --git a/interpreter.py b/interpreter.py index 8fa35857f..82bcf52cd 100755 --- a/interpreter.py +++ b/interpreter.py @@ -38,7 +38,16 @@ class BuildTarget(InterpreterObject): self.name = name self.sources = sources self.external_deps = [] - self.methods = {'add_dep': self.add_dep_method} + self.methods = {'add_dep': self.add_dep_method, + 'link' : self.link_method} + self.link_targets = [] + self.filename = 'no_name' + + def get_filename(self): + return self.filename + + def get_dependencies(self): + return self.link_targets def get_basename(self): return self.name @@ -54,22 +63,45 @@ class BuildTarget(InterpreterObject): def get_external_deps(self): return self.external_deps - def add_dep_method(self, method_name, args): + def add_dep_method(self, args): [self.add_external_dep(dep) for dep in args] + def link_method(self, args): + target = args[0] + if not isinstance(target, StaticLibrary) and \ + not isinstance(target, SharedLibrary): + raise InvalidArguments('Link target is not library.') + self.link_targets.append(target) + def method_call(self, method_name, args): if method_name in self.methods: - return self.methods[method_name](self, args) + return self.methods[method_name](args) raise InvalidCode('Unknown method "%s" in BuildTarget.' % method_name) + class Executable(BuildTarget): - pass + def __init__(self, name, sources, environment): + BuildTarget.__init__(self, name, sources) + suffix = environment.get_exe_suffix() + if suffix != '': + self.filename = self.name + '.' + suffix + else: + self.filename = self.name + class StaticLibrary(BuildTarget): - pass + def __init__(self, name, sources, environment): + BuildTarget.__init__(self, name, sources) + prefix = environment.get_static_lib_prefix() + suffix = environment.get_static_lib_suffix() + self.filename = prefix + self.name + '.' + suffix class SharedLibrary(BuildTarget): - pass + def __init__(self, name, sources, environment): + BuildTarget.__init__(self, name, sources) + prefix = environment.get_shared_lib_prefix() + suffix = environment.get_shared_lib_suffix() + self.filename = prefix + self.name + '.' + suffix class Interpreter(): @@ -182,7 +214,7 @@ class Interpreter(): sources = args[1:] if name in self.targets: raise InvalidCode('Line %d: tried to create target "%s", but a target of that name already exists.' % (node.lineno(), name)) - l = targetclass(name, sources) + l = targetclass(name, sources, self.environment) self.targets[name] = l print('Creating build target "%s" with %d files.' % (name, len(sources))) return l diff --git a/shellgenerator.py b/shellgenerator.py index ac8c9879d..f115fbe94 100755 --- a/shellgenerator.py +++ b/shellgenerator.py @@ -26,7 +26,8 @@ class ShellGenerator(): self.environment = environment self.interpreter = interpreter self.build_filename = 'compile.sh' - + self.processed_targets = {} + def generate(self): self.interpreter.run() outfilename = os.path.join(self.environment.get_build_dir(), self.build_filename) @@ -69,6 +70,15 @@ class ShellGenerator(): outfile.write('\necho Compiling \\"%s\\"\n' % src) outfile.write(' '.join(quoted) + ' || exit\n') return abs_obj + + def build_target_link_arguments(self, deps): + args = [] + for d in deps: + if not isinstance(d, interpreter.StaticLibrary): + print(d) + raise RuntimeError('Only static libraries supported ATM.') + args.append(self.get_target_filename(d)) + return args def generate_link(self, target, outfile, outname, obj_list): if isinstance(target, interpreter.StaticLibrary): @@ -91,6 +101,7 @@ class ShellGenerator(): commands += linker.get_output_flags() commands.append(outname) commands += obj_list + commands += self.build_target_link_arguments(target.get_dependencies()) quoted = shell_quote(commands) outfile.write('\necho Linking \\"%s\\".\n' % target.get_basename()) outfile.write(' '.join(quoted) + ' || exit\n') @@ -102,27 +113,32 @@ class ShellGenerator(): def generate_commands(self, outfile): for i in self.interpreter.get_targets().items(): - name = i[0] target = i[1] - print('Generating target', name) - targetdir = self.get_target_dir(target) - prefix = '' - suffix = '' - if isinstance(target, interpreter.Executable): - suffix = self.environment.get_exe_suffix() - elif isinstance(target, interpreter.StaticLibrary): - prefix = self.environment.get_static_lib_prefix() - suffix = self.environment.get_static_lib_suffix() - elif isinstance(target, interpreter.SharedLibrary): - prefix = self.environment.get_shared_lib_prefix() - suffix = self.environment.get_shared_lib_suffix() - outname = os.path.join(targetdir, prefix + target.get_basename()) - if suffix != '': - outname = outname + '.' + suffix - obj_list = [] - for src in target.get_sources(): - obj_list.append(self.generate_single_compile(target, outfile, src)) - self.generate_link(target, outfile, outname, obj_list) + self.generate_target(target, outfile) + + def process_target_dependencies(self, target, outfile): + for t in target.get_dependencies(): + tname = t.get_basename() + if not tname in self.processed_targets: + self.generate_target(t, outfile) + + def get_target_filename(self, target): + targetdir = self.get_target_dir(target) + filename = os.path.join(targetdir, target.get_filename()) + return filename + + def generate_target(self, target, outfile): + name = target.get_basename() + if name in self.processed_targets: + return + self.process_target_dependencies(target, outfile) + print('Generating target', name) + outname = self.get_target_filename(target) + obj_list = [] + for src in target.get_sources(): + obj_list.append(self.generate_single_compile(target, outfile, src)) + self.generate_link(target, outfile, outname, obj_list) + self.processed_targets[name] = True if __name__ == '__main__': code = """ diff --git a/test cases/5 linkstatic/builder.txt b/test cases/5 linkstatic/builder.txt new file mode 100644 index 000000000..5e98a2518 --- /dev/null +++ b/test cases/5 linkstatic/builder.txt @@ -0,0 +1,5 @@ +project('static library linking test') +language('c') +lib = static_library('mylib', 'libfile.c') +exe = executable('prog', 'main.c') +exe.link(lib) diff --git a/test cases/5 linkstatic/libfile.c b/test cases/5 linkstatic/libfile.c new file mode 100644 index 000000000..6f1c172d6 --- /dev/null +++ b/test cases/5 linkstatic/libfile.c @@ -0,0 +1,3 @@ +int func() { + return 0; +} diff --git a/test cases/5 linkstatic/main.c b/test cases/5 linkstatic/main.c new file mode 100644 index 000000000..8aadb0c7c --- /dev/null +++ b/test cases/5 linkstatic/main.c @@ -0,0 +1,5 @@ +int func(); + +int main(int argc, char **arg) { + return func(); +}