1# Copyright 2014 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load(
16 "//go/private:common.bzl",
17 "as_tuple",
18 "split_srcs",
19)
20load(
21 "//go/private:mode.bzl",
22 "LINKMODE_C_ARCHIVE",
23 "LINKMODE_C_SHARED",
24 "mode_string",
25)
26load(
27 "//go/private:providers.bzl",
28 "GoArchive",
29 "GoArchiveData",
30 "effective_importpath_pkgpath",
31 "get_archive",
32)
33load(
34 "//go/private/rules:cgo.bzl",
35 "cgo_configure",
36)
37load(
38 "//go/private/actions:compilepkg.bzl",
39 "emit_compilepkg",
40)
41
42def emit_archive(go, source = None, _recompile_suffix = "", recompile_internal_deps = None):
43 """See go/toolchains.rst#archive for full documentation."""
44
45 if source == None:
46 fail("source is a required parameter")
47
48 split = split_srcs(source.srcs)
49 testfilter = getattr(source.library, "testfilter", None)
50 pre_ext = ""
51 if go.mode.link == LINKMODE_C_ARCHIVE:
52 pre_ext = "_" # avoid collision with go_binary output file with .a extension
53 elif testfilter == "exclude":
54 pre_ext = ".internal"
55 elif testfilter == "only":
56 pre_ext = ".external"
57 if _recompile_suffix:
58 pre_ext += _recompile_suffix
59 out_lib = go.declare_file(go, name = source.library.name, ext = pre_ext + ".a")
60
61 # store export information for compiling dependent packages separately
62 out_export = go.declare_file(go, name = source.library.name, ext = pre_ext + ".x")
63 out_cgo_export_h = None # set if cgo used in c-shared or c-archive mode
64 out_facts = None
65 nogo = go.get_nogo(go)
66 if nogo:
67 out_facts = go.declare_file(go, name = source.library.name, ext = pre_ext + ".facts")
68
69 direct = [get_archive(dep) for dep in source.deps]
70 runfiles = source.runfiles
71 data_files = runfiles.files
72
73 files = []
74 for a in direct:
75 files.append(a.runfiles)
76 if a.source.mode != go.mode:
77 fail("Archive mode does not match {} is {} expected {}".format(a.data.label, mode_string(a.source.mode), mode_string(go.mode)))
78 runfiles.merge_all(files)
79
80 importmap = "main" if source.library.is_main else source.library.importmap
81 importpath, _ = effective_importpath_pkgpath(source.library)
82
83 if source.cgo and not go.mode.pure:
84 # TODO(jayconrod): do we need to do full Bourne tokenization here?
85 cppopts = [f for fs in source.cppopts for f in fs.split(" ")]
86 copts = [f for fs in source.copts for f in fs.split(" ")]
87 cxxopts = [f for fs in source.cxxopts for f in fs.split(" ")]
88 clinkopts = [f for fs in source.clinkopts for f in fs.split(" ")]
89 cgo = cgo_configure(
90 go,
91 srcs = split.go + split.c + split.asm + split.cxx + split.objc + split.headers,
92 cdeps = source.cdeps,
93 cppopts = cppopts,
94 copts = copts,
95 cxxopts = cxxopts,
96 clinkopts = clinkopts,
97 )
98 if go.mode.link in (LINKMODE_C_SHARED, LINKMODE_C_ARCHIVE):
99 out_cgo_export_h = go.declare_file(go, path = "_cgo_install.h")
100 cgo_deps = cgo.deps
101 runfiles = runfiles.merge(cgo.runfiles)
102 emit_compilepkg(
103 go,
104 sources = split.go + split.c + split.asm + split.cxx + split.objc + split.headers,
105 cover = source.cover,
106 embedsrcs = source.embedsrcs,
107 importpath = importpath,
108 importmap = importmap,
109 archives = direct,
110 out_lib = out_lib,
111 out_export = out_export,
112 out_facts = out_facts,
113 nogo = nogo,
114 out_cgo_export_h = out_cgo_export_h,
115 gc_goopts = source.gc_goopts,
116 cgo = True,
117 cgo_inputs = cgo.inputs,
118 cppopts = cgo.cppopts,
119 copts = cgo.copts,
120 cxxopts = cgo.cxxopts,
121 objcopts = cgo.objcopts,
122 objcxxopts = cgo.objcxxopts,
123 clinkopts = cgo.clinkopts,
124 testfilter = testfilter,
125 )
126 else:
127 cgo_deps = depset()
128 emit_compilepkg(
129 go,
130 sources = split.go + split.c + split.asm + split.cxx + split.objc + split.headers,
131 cover = source.cover,
132 embedsrcs = source.embedsrcs,
133 importpath = importpath,
134 importmap = importmap,
135 archives = direct,
136 out_lib = out_lib,
137 out_export = out_export,
138 out_facts = out_facts,
139 nogo = nogo,
140 gc_goopts = source.gc_goopts,
141 cgo = False,
142 testfilter = testfilter,
143 recompile_internal_deps = recompile_internal_deps,
144 )
145
146 data = GoArchiveData(
147 # TODO(#2578): reconsider the provider API. There's a lot of redundant
148 # information here. Some fields are tuples instead of lists or dicts
149 # since GoArchiveData is stored in a depset, and no value in a depset
150 # may be mutable. For now, new copied fields are private (named with
151 # a leading underscore) since they may change in the future.
152
153 # GoLibrary fields
154 name = source.library.name,
155 label = source.library.label,
156 importpath = source.library.importpath,
157 importmap = source.library.importmap,
158 importpath_aliases = source.library.importpath_aliases,
159 pathtype = source.library.pathtype,
160
161 # GoSource fields
162 srcs = as_tuple(source.srcs),
163 orig_srcs = as_tuple(source.orig_srcs),
164 _orig_src_map = tuple([source.orig_src_map.get(src, src) for src in source.srcs]),
165 _cover = as_tuple(source.cover),
166 _embedsrcs = as_tuple(source.embedsrcs),
167 _x_defs = tuple(source.x_defs.items()),
168 _gc_goopts = as_tuple(source.gc_goopts),
169 _cgo = source.cgo,
170 _cdeps = as_tuple(source.cdeps),
171 _cppopts = as_tuple(source.cppopts),
172 _copts = as_tuple(source.copts),
173 _cxxopts = as_tuple(source.cxxopts),
174 _clinkopts = as_tuple(source.clinkopts),
175 _cgo_exports = as_tuple(source.cgo_exports),
176
177 # Information on dependencies
178 _dep_labels = tuple([d.data.label for d in direct]),
179 _dep_importmaps = tuple([d.data.importmap for d in direct]),
180
181 # Information needed by dependents
182 file = out_lib,
183 export_file = out_export,
184 facts_file = out_facts,
185 data_files = as_tuple(data_files),
186 _cgo_deps = as_tuple(cgo_deps),
187 )
188 x_defs = dict(source.x_defs)
189 for a in direct:
190 x_defs.update(a.x_defs)
191 cgo_exports_direct = list(source.cgo_exports)
192
193 # Ensure that the _cgo_export.h of the current target comes first when cgo_exports is iterated
194 # by prepending it and specifying the order explicitly. This is required as the CcInfo attached
195 # to the archive only exposes a single header rather than combining all headers.
196 if out_cgo_export_h:
197 cgo_exports_direct.insert(0, out_cgo_export_h)
198 cgo_exports = depset(direct = cgo_exports_direct, transitive = [a.cgo_exports for a in direct], order = "preorder")
199 return GoArchive(
200 source = source,
201 data = data,
202 direct = direct,
203 libs = depset(direct = [out_lib], transitive = [a.libs for a in direct]),
204 transitive = depset([data], transitive = [a.transitive for a in direct]),
205 x_defs = x_defs,
206 cgo_deps = depset(transitive = [cgo_deps] + [a.cgo_deps for a in direct]),
207 cgo_exports = cgo_exports,
208 runfiles = runfiles,
209 mode = go.mode,
210 )
View as plain text