blob: 8e6d561d56b314063266ae3d9b5b512cc11d86d4 [file] [log] [blame]
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""These are bare-bones Go rules.
Several issues:
- Dependencies are not enforced; a symlink tree might help here too.
- Hardcoded to 6g from the GC suite. We should be able to support GCC
and derive 6g from the CPU (from which configuration?)
- It would be nice to be able to create a full-fledged Go
configuration in Skylark.
- It would be nice to support zero-configuration rules, similar to
vanilla "go", with one package per directory. This would requiere
macro support though, to use glob()
* For "a/b/c.go", the go tool creates library "a/b.a" with import path
"a/b". We can probably simulate this with symlink trees.
- does not support checked in compilers.
- No C++ interop.
- deps must be populated by hand.
- go_test must have both test and non-test files in srcs.
"""
go_filetype = FileType([".go"])
go_lib_filetype = FileType([".a"])
def go_compile_command(ctx, sources, out_lib):
args = [
ctx.files.go_root[0].path + "/bin/go",
"tool", "6g",
"-o", out_lib.path, "-pack",
# Import path.
"-I", ctx.configuration.bin_dir.path]
# Set -p to the import path of the library, ie.
# (ctx.label.package + "/" ctx.label.name) for now.
return ' '.join(args + cmd_helper.template(sources, "%{path}"))
def go_library_impl(ctx):
sources = ctx.files.srcs
if not sources:
fail("may not be empty", "srcs")
out_lib = ctx.outputs.lib
ctx.action(
inputs = sources + ctx.files.deps,
outputs = [out_lib],
mnemonic = "GoCompile",
env = {
"GOROOT": ctx.files.go_root[0].path,
},
command = go_compile_command(ctx, set(sources), out_lib))
out_nset = set([out_lib])
return struct(
files = out_nset,
go_library_object = out_nset)
def go_link_action(ctx, lib, executable):
cmd = ' '.join([
ctx.files.go_root[0].path + "/bin/go",
"tool", "6l",
# Link search path.
"-L", ctx.configuration.bin_dir.path,
"-o", executable.path,
lib.path])
ctx.action(
inputs = [lib],
outputs = [executable],
command = cmd,
env = {
"GOROOT": ctx.files.go_root[0].path,
},
mnemonic = "GoLink")
def go_binary_impl(ctx):
lib_result = go_library_impl(ctx)
executable = ctx.outputs.executable
lib_out = ctx.outputs.lib
go_link_action(ctx, lib_out, executable)
return struct(files = set([executable]) + lib_result.files)
def go_test_impl(ctx):
lib_result = go_library_impl(ctx)
main_go = ctx.outputs.main_go
go_import = ctx.label.package + "/" + ctx.label.name
# Would be nice to use transitive info provider to get at sources of
# a dependent library.
sources = ctx.files.srcs
args = (["--package", go_import, "--output", ctx.outputs.main_go.path] +
cmd_helper.template(set(sources), "%{path}"))
ctx.action(
inputs = sources,
executable = ctx.executable.test_generator,
outputs = [main_go],
mnemonic = "GoTestGenTest",
arguments = args)
ctx.action(
inputs = [main_go, ctx.outputs.lib],
outputs = [ctx.outputs.main_lib],
command = go_compile_command(ctx, set([main_go]), ctx.outputs.main_lib),
env = {
"GOROOT": ctx.files.go_root[0].path,
},
mnemonic = "GoCompileTest")
go_link_action(ctx, ctx.outputs.main_lib, ctx.outputs.executable)
runfiles = ctx.runfiles(collect_data = True, files = [ctx.outputs.executable])
return struct(runfiles=runfiles)
go_library_attrs = {
"data": attr.label_list(allow_files=True, cfg=DATA_CFG),
"srcs": attr.label_list(allow_files=go_filetype),
"deps": attr.label_list(
providers=["go_library_object"]),
"go_root": attr.label(
default=Label("//tools/go:go_root"),
allow_files=True,
cfg=HOST_CFG),
}
go_library_outputs = {
"lib": "%{name}.a",
}
go_library = rule(
go_library_impl,
attrs = go_library_attrs,
outputs =go_library_outputs)
go_binary = rule(
go_binary_impl,
executable = True,
attrs = go_library_attrs,
outputs = go_library_outputs)
go_test = rule(
go_test_impl,
executable = True,
test = True,
attrs = go_library_attrs + {
"test_generator": attr.label(
default=Label("//tools/go:generate_test_main"),
cfg=HOST_CFG, flags=["EXECUTABLE"])
},
outputs = {
"lib" : "%{name}.a",
"main_lib": "%{name}_main_test.a",
"main_go": "%{name}_main_test.go",
})