1*9bb1b549SSpandan Das# Copyright 2014 The Bazel Authors. All rights reserved. 2*9bb1b549SSpandan Das# 3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License"); 4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License. 5*9bb1b549SSpandan Das# You may obtain a copy of the License at 6*9bb1b549SSpandan Das# 7*9bb1b549SSpandan Das# http://www.apache.org/licenses/LICENSE-2.0 8*9bb1b549SSpandan Das# 9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software 10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS, 11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and 13*9bb1b549SSpandan Das# limitations under the License. 14*9bb1b549SSpandan Das 15*9bb1b549SSpandan Dasload( 16*9bb1b549SSpandan Das "//go/private:common.bzl", 17*9bb1b549SSpandan Das "get_versioned_shared_lib_extension", 18*9bb1b549SSpandan Das "has_simple_shared_lib_extension", 19*9bb1b549SSpandan Das "hdr_exts", 20*9bb1b549SSpandan Das) 21*9bb1b549SSpandan Dasload( 22*9bb1b549SSpandan Das "//go/private:mode.bzl", 23*9bb1b549SSpandan Das "LINKMODE_NORMAL", 24*9bb1b549SSpandan Das "extldflags_from_cc_toolchain", 25*9bb1b549SSpandan Das) 26*9bb1b549SSpandan Das 27*9bb1b549SSpandan Dasdef cgo_configure(go, srcs, cdeps, cppopts, copts, cxxopts, clinkopts): 28*9bb1b549SSpandan Das """cgo_configure returns the inputs and compile / link options 29*9bb1b549SSpandan Das that are required to build a cgo archive. 30*9bb1b549SSpandan Das 31*9bb1b549SSpandan Das Args: 32*9bb1b549SSpandan Das go: a GoContext. 33*9bb1b549SSpandan Das srcs: list of source files being compiled. Include options are added 34*9bb1b549SSpandan Das for the headers. 35*9bb1b549SSpandan Das cdeps: list of Targets for C++ dependencies. Include and link options 36*9bb1b549SSpandan Das may be added. 37*9bb1b549SSpandan Das cppopts: list of C preprocessor options for the library. 38*9bb1b549SSpandan Das copts: list of C compiler options for the library. 39*9bb1b549SSpandan Das cxxopts: list of C++ compiler options for the library. 40*9bb1b549SSpandan Das clinkopts: list of linker options for the library. 41*9bb1b549SSpandan Das 42*9bb1b549SSpandan Das Returns: a struct containing: 43*9bb1b549SSpandan Das inputs: depset of files that must be available for the build. 44*9bb1b549SSpandan Das deps: depset of files for dynamic libraries. 45*9bb1b549SSpandan Das runfiles: runfiles object for the C/C++ dependencies. 46*9bb1b549SSpandan Das cppopts: complete list of preprocessor options 47*9bb1b549SSpandan Das copts: complete list of C compiler options. 48*9bb1b549SSpandan Das cxxopts: complete list of C++ compiler options. 49*9bb1b549SSpandan Das objcopts: complete list of Objective-C compiler options. 50*9bb1b549SSpandan Das objcxxopts: complete list of Objective-C++ compiler options. 51*9bb1b549SSpandan Das clinkopts: complete list of linker options. 52*9bb1b549SSpandan Das """ 53*9bb1b549SSpandan Das if not go.cgo_tools: 54*9bb1b549SSpandan Das fail("Go toolchain does not support cgo") 55*9bb1b549SSpandan Das 56*9bb1b549SSpandan Das cppopts = list(cppopts) 57*9bb1b549SSpandan Das copts = go.cgo_tools.c_compile_options + copts 58*9bb1b549SSpandan Das cxxopts = go.cgo_tools.cxx_compile_options + cxxopts 59*9bb1b549SSpandan Das objcopts = go.cgo_tools.objc_compile_options + copts 60*9bb1b549SSpandan Das objcxxopts = go.cgo_tools.objcxx_compile_options + cxxopts 61*9bb1b549SSpandan Das clinkopts = extldflags_from_cc_toolchain(go) + clinkopts 62*9bb1b549SSpandan Das 63*9bb1b549SSpandan Das # NOTE(#2545): avoid unnecessary dynamic link 64*9bb1b549SSpandan Das if "-static-libstdc++" in clinkopts: 65*9bb1b549SSpandan Das clinkopts = [ 66*9bb1b549SSpandan Das option 67*9bb1b549SSpandan Das for option in clinkopts 68*9bb1b549SSpandan Das if option not in ("-lstdc++", "-lc++") 69*9bb1b549SSpandan Das ] 70*9bb1b549SSpandan Das 71*9bb1b549SSpandan Das if go.mode != LINKMODE_NORMAL: 72*9bb1b549SSpandan Das for opt_list in (copts, cxxopts, objcopts, objcxxopts): 73*9bb1b549SSpandan Das if "-fPIC" not in opt_list: 74*9bb1b549SSpandan Das opt_list.append("-fPIC") 75*9bb1b549SSpandan Das 76*9bb1b549SSpandan Das seen_includes = {} 77*9bb1b549SSpandan Das seen_quote_includes = {} 78*9bb1b549SSpandan Das seen_system_includes = {} 79*9bb1b549SSpandan Das have_hdrs = any([f.basename.endswith(ext) for f in srcs for ext in hdr_exts]) 80*9bb1b549SSpandan Das if have_hdrs: 81*9bb1b549SSpandan Das # Add include paths for all sources so we can use include paths relative 82*9bb1b549SSpandan Das # to any source file or any header file. The go command requires all 83*9bb1b549SSpandan Das # sources to be in the same directory, but that's not necessarily the 84*9bb1b549SSpandan Das # case here. 85*9bb1b549SSpandan Das # 86*9bb1b549SSpandan Das # Use -I so either <> or "" includes may be used (same as go command). 87*9bb1b549SSpandan Das for f in srcs: 88*9bb1b549SSpandan Das _include_unique(cppopts, "-I", f.dirname, seen_includes) 89*9bb1b549SSpandan Das 90*9bb1b549SSpandan Das inputs_direct = [] 91*9bb1b549SSpandan Das inputs_transitive = [] 92*9bb1b549SSpandan Das deps_direct = [] 93*9bb1b549SSpandan Das lib_opts = [] 94*9bb1b549SSpandan Das runfiles = go._ctx.runfiles(collect_data = True) 95*9bb1b549SSpandan Das 96*9bb1b549SSpandan Das # Always include the sandbox as part of the build. Bazel does this, but it 97*9bb1b549SSpandan Das # doesn't appear in the CompilationContext. 98*9bb1b549SSpandan Das _include_unique(cppopts, "-iquote", ".", seen_quote_includes) 99*9bb1b549SSpandan Das for d in cdeps: 100*9bb1b549SSpandan Das runfiles = runfiles.merge(d.data_runfiles) 101*9bb1b549SSpandan Das if CcInfo in d: 102*9bb1b549SSpandan Das cc_transitive_headers = d[CcInfo].compilation_context.headers 103*9bb1b549SSpandan Das inputs_transitive.append(cc_transitive_headers) 104*9bb1b549SSpandan Das cc_libs, cc_link_flags = _cc_libs_and_flags(d) 105*9bb1b549SSpandan Das inputs_direct.extend(cc_libs) 106*9bb1b549SSpandan Das deps_direct.extend(cc_libs) 107*9bb1b549SSpandan Das cc_defines = d[CcInfo].compilation_context.defines.to_list() 108*9bb1b549SSpandan Das cppopts.extend(["-D" + define for define in cc_defines]) 109*9bb1b549SSpandan Das cc_includes = d[CcInfo].compilation_context.includes.to_list() 110*9bb1b549SSpandan Das for inc in cc_includes: 111*9bb1b549SSpandan Das _include_unique(cppopts, "-I", inc, seen_includes) 112*9bb1b549SSpandan Das cc_quote_includes = d[CcInfo].compilation_context.quote_includes.to_list() 113*9bb1b549SSpandan Das for inc in cc_quote_includes: 114*9bb1b549SSpandan Das _include_unique(cppopts, "-iquote", inc, seen_quote_includes) 115*9bb1b549SSpandan Das cc_system_includes = d[CcInfo].compilation_context.system_includes.to_list() 116*9bb1b549SSpandan Das for inc in cc_system_includes: 117*9bb1b549SSpandan Das _include_unique(cppopts, "-isystem", inc, seen_system_includes) 118*9bb1b549SSpandan Das for lib in cc_libs: 119*9bb1b549SSpandan Das # If both static and dynamic variants are available, Bazel will only give 120*9bb1b549SSpandan Das # us the static variant. We'll get one file for each transitive dependency, 121*9bb1b549SSpandan Das # so the same file may appear more than once. 122*9bb1b549SSpandan Das if lib.basename.startswith("lib"): 123*9bb1b549SSpandan Das if has_simple_shared_lib_extension(lib.basename): 124*9bb1b549SSpandan Das # If the loader would be able to find the library using rpaths, 125*9bb1b549SSpandan Das # use -L and -l instead of hard coding the path to the library in 126*9bb1b549SSpandan Das # the binary. This gives users more flexibility. The linker will add 127*9bb1b549SSpandan Das # rpaths later. We can't add them here because they are relative to 128*9bb1b549SSpandan Das # the binary location, and we don't know where that is. 129*9bb1b549SSpandan Das libname = lib.basename[len("lib"):lib.basename.rindex(".")] 130*9bb1b549SSpandan Das clinkopts.extend(["-L", lib.dirname, "-l", libname]) 131*9bb1b549SSpandan Das inputs_direct.append(lib) 132*9bb1b549SSpandan Das continue 133*9bb1b549SSpandan Das extension = get_versioned_shared_lib_extension(lib.basename) 134*9bb1b549SSpandan Das if extension.startswith("so"): 135*9bb1b549SSpandan Das # With a versioned .so file, we must use the full filename, 136*9bb1b549SSpandan Das # otherwise the library will not be found by the linker. 137*9bb1b549SSpandan Das libname = ":%s" % lib.basename 138*9bb1b549SSpandan Das clinkopts.extend(["-L", lib.dirname, "-l", libname]) 139*9bb1b549SSpandan Das inputs_direct.append(lib) 140*9bb1b549SSpandan Das continue 141*9bb1b549SSpandan Das elif extension.startswith("dylib"): 142*9bb1b549SSpandan Das # A standard versioned dylib is named as libMagick.2.dylib, which is 143*9bb1b549SSpandan Das # treated as a simple shared library. Non-standard versioned dylibs such as 144*9bb1b549SSpandan Das # libclntsh.dylib.12.1, users have to create a unversioned symbolic link, 145*9bb1b549SSpandan Das # so it can be treated as a simple shared library too. 146*9bb1b549SSpandan Das continue 147*9bb1b549SSpandan Das lib_opts.append(lib.path) 148*9bb1b549SSpandan Das clinkopts.extend(cc_link_flags) 149*9bb1b549SSpandan Das 150*9bb1b549SSpandan Das elif hasattr(d, "objc"): 151*9bb1b549SSpandan Das cppopts.extend(["-D" + define for define in d.objc.define.to_list()]) 152*9bb1b549SSpandan Das for inc in d.objc.include.to_list(): 153*9bb1b549SSpandan Das _include_unique(cppopts, "-I", inc, seen_includes) 154*9bb1b549SSpandan Das for inc in d.objc.iquote.to_list(): 155*9bb1b549SSpandan Das _include_unique(cppopts, "-iquote", inc, seen_quote_includes) 156*9bb1b549SSpandan Das for inc in d.objc.include_system.to_list(): 157*9bb1b549SSpandan Das _include_unique(cppopts, "-isystem", inc, seen_system_includes) 158*9bb1b549SSpandan Das 159*9bb1b549SSpandan Das # TODO(jayconrod): do we need to link against dynamic libraries or 160*9bb1b549SSpandan Das # frameworks? We link against *_fully_linked.a, so maybe not? 161*9bb1b549SSpandan Das 162*9bb1b549SSpandan Das else: 163*9bb1b549SSpandan Das fail("unknown library has neither cc nor objc providers: %s" % d.label) 164*9bb1b549SSpandan Das 165*9bb1b549SSpandan Das inputs = depset(direct = inputs_direct, transitive = inputs_transitive) 166*9bb1b549SSpandan Das deps = depset(direct = deps_direct) 167*9bb1b549SSpandan Das 168*9bb1b549SSpandan Das # HACK: some C/C++ toolchains will ignore libraries (including dynamic libs 169*9bb1b549SSpandan Das # specified with -l flags) unless they appear after .o or .a files with 170*9bb1b549SSpandan Das # undefined symbols they provide. Put all the .a files from cdeps first, 171*9bb1b549SSpandan Das # so that we actually link with -lstdc++ and others. 172*9bb1b549SSpandan Das clinkopts = lib_opts + clinkopts 173*9bb1b549SSpandan Das 174*9bb1b549SSpandan Das return struct( 175*9bb1b549SSpandan Das inputs = inputs, 176*9bb1b549SSpandan Das deps = deps, 177*9bb1b549SSpandan Das runfiles = runfiles, 178*9bb1b549SSpandan Das cppopts = cppopts, 179*9bb1b549SSpandan Das copts = copts, 180*9bb1b549SSpandan Das cxxopts = cxxopts, 181*9bb1b549SSpandan Das objcopts = objcopts, 182*9bb1b549SSpandan Das objcxxopts = objcxxopts, 183*9bb1b549SSpandan Das clinkopts = clinkopts, 184*9bb1b549SSpandan Das ) 185*9bb1b549SSpandan Das 186*9bb1b549SSpandan Dasdef _cc_libs_and_flags(target): 187*9bb1b549SSpandan Das # Copied from get_libs_for_static_executable in migration instructions 188*9bb1b549SSpandan Das # from bazelbuild/bazel#7036. 189*9bb1b549SSpandan Das libs = [] 190*9bb1b549SSpandan Das flags = [] 191*9bb1b549SSpandan Das for li in target[CcInfo].linking_context.linker_inputs.to_list(): 192*9bb1b549SSpandan Das flags.extend(li.user_link_flags) 193*9bb1b549SSpandan Das for library_to_link in li.libraries: 194*9bb1b549SSpandan Das if library_to_link.static_library != None: 195*9bb1b549SSpandan Das libs.append(library_to_link.static_library) 196*9bb1b549SSpandan Das elif library_to_link.pic_static_library != None: 197*9bb1b549SSpandan Das libs.append(library_to_link.pic_static_library) 198*9bb1b549SSpandan Das elif library_to_link.interface_library != None: 199*9bb1b549SSpandan Das libs.append(library_to_link.interface_library) 200*9bb1b549SSpandan Das elif library_to_link.dynamic_library != None: 201*9bb1b549SSpandan Das libs.append(library_to_link.dynamic_library) 202*9bb1b549SSpandan Das return libs, flags 203*9bb1b549SSpandan Das 204*9bb1b549SSpandan Dasdef _include_unique(opts, flag, include, seen): 205*9bb1b549SSpandan Das if include in seen: 206*9bb1b549SSpandan Das return 207*9bb1b549SSpandan Das seen[include] = True 208*9bb1b549SSpandan Das opts.extend([flag, include]) 209