Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various fixes and changes #1340

Merged
merged 15 commits into from Feb 28, 2018
Merged

Various fixes and changes #1340

merged 15 commits into from Feb 28, 2018

Conversation

steeve
Copy link
Contributor

@steeve steeve commented Feb 21, 2018

This PR is a mix of various changes and fixes we've made on https://github.com/znly/rules_go that I think are upstream-able first. Of course we can split and shrink if you guys want.

Here goes:
36bc7cc: Add runfiles to GoArchiveData and use them in the GoPath
Some binaries (such as https://github.com/golang/mobile/tree/master/cmd/gobind) rely on runtime files to be in the GOPATH

060c171: Expose GoPath provider
Title says it all. Useful for custom rules.

f59a93d: Add tags and environment to go_context
Title says it all.

e4a157e: Expose GoSource provider
Title says it all. Useful for custom rules.

7d1d956: Make the Go environment an update of the OS environment
This ensures that the Go environment also has the OS environment keys.

f789bcd: Propagate build tags when go installing stdlib
std has a few tags here and there (for instance crypto/x509 needs the ios tag to build on darwin_arm64). This makes sure they are propagated.

93ce009: Make stdlib building depend on CROSSTOOL (for runtime/cgo)
runtime/cgo needs the C compiler, and it's not declared as a dependency. As a result, when using a different CROSSTOOL (such as Android), it will fail to find the compiler (clang).

aad1ce3: extras/bindata: make it executable and run on host
Needed to use cross compilation (via --platforms) and bindata.

@bazel-io
Copy link

Can one of the admins verify this patch?

@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this State. It's up to you to confirm consent of the commit author(s) and merge this pull request when appropriate.

@zllak
Copy link
Contributor

zllak commented Feb 21, 2018

I am the author of one of the commits, it's part of a join effort with @steeve 👍

k, v := pair[0], pair[1]
retEnvMap[k] = v
}
for _, e := range new {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i should not use new as a var name

@jayconrod jayconrod self-assigned this Feb 21, 2018
Copy link
Contributor

@jayconrod jayconrod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in review. Mostly looks good, but I have a few questions and suggested changes.

There are also a few test failures. You can run our CI tests with bazel test //....

@ianthehat may also have some comments.

@@ -86,6 +86,7 @@ def emit_archive(go, source=None):
file = out_lib,
srcs = as_tuple(source.srcs),
searchpath = searchpath,
runfiles = runfiles,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of putting runfiles in GoArchiveData, I think it would be better to use the runfiles already in GoArchive or in DefaultInfo.

The reason for the split between GoArchive and GoArchiveData is avoiding O(n^2) blowup when accumulating information from a large graph of dependencies. GoArchiveData contains information about a single archive. GoArchive contains information about an archive and all of its transitive dependencies. runfiles is a better fit in GoArchive for this reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

@@ -75,7 +75,7 @@ Found {} in
seen_libs[golib.importpath] = golib
package_files = []
prefix = "src/" + golib.importpath + "/"
for src in golib.srcs:
for src in as_iterable(golib.srcs) + tuple(as_iterable(golib.runfiles.files)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than modifying this loop, create a runfiles object above (where golibs is accumulated) and merge in the runfiles from each archive. Then iterate over that in a separate loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure thing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing is that i need the importpath to put them in the fake gopath properly, so keeping the archives is rather useful

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, makes sense. There needs to be some association between the import path and the data files, but we need to avoid placing runfiles in GoArchiveData to avoid a blowup in data structure size and time to iterate.

Instead of adding runfiles to GoArchiveData, I'd suggest adding a data field, which will be a tuple of data files just for that archive. This will be essentially the same format as srcs. You can get this tuple in emit_archive by iterating source.runfiles before it's merged.

@@ -74,6 +74,7 @@ def _new_args(go):
"-goarch", go.mode.goarch,
"-cgo=" + ("0" if go.mode.pure else "1"),
])
args.add(go.tags, before_each = "-tags")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env.go expects -tags to be a comma separated list. It can't be repeated. I think args.add(go.tags, join_with=",") would be correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call! thanks

@@ -267,13 +270,17 @@ def _go_context_data(ctx):
linker_options = [o for o in raw_linker_options if not o in [
"-Wl,--gc-sections",
]]
env = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would go here in the future? We generally want to avoid pulling anything out of the user's environment, since that makes builds less reproducible.

Copy link
Contributor Author

@steeve steeve Feb 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not about pulling the user's environment, but rather merging the rule environment with the builder's or go install based rules such as stdlib

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that makes sense.

@@ -267,13 +270,17 @@ def _go_context_data(ctx):
linker_options = [o for o in raw_linker_options if not o in [
"-Wl,--gc-sections",
]]
env = {}
tags = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the best way to populate this is by reading ctx.var["gotags"] or something similar. Users could set tags with --define=gotags=foo,bar,baz on the command line or in an rc file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be added later, but the main case for me to use it since the builders can too.
also, when building for ios, both tags and env need to be properly set up, and in that case I'm doing it from inside the rules themselves

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually ctx.var["gotags"] or [] is rather easy to do, i'm sold

@@ -23,6 +23,8 @@ load(
load(
"@io_bazel_rules_go//go/private:providers.bzl",
_GoLibrary = "GoLibrary",
_GoSource = "GoSource",
_GoPath = "GoPath",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to expose GoArchive and GoArchiveData, too. They're documented and fairly stable at this point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome

pair := strings.SplitN(e, "=", 2)
k, v := pair[0], pair[1]
if preV := retEnvMap[k]; preV != "" {
retEnvMap[k] = preV + " " + v
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scares me. Seems like we could end up with GOOS=linux linux or something. Why is this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is true. however, both ends (old and new) are controlled by rules_go. But in the case of CGO_CFLAGS for instance, we could get to the case when it would get overridden instead of merged

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by both end I mean the skylark and go builder side

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think I understand this better. I'm still concerned that it's prone to duplication. I don't think there's a situation where we actually need to merge flags in the same environment variable. Here's what I think we should do:

  • Any value that any builder needs to handle explicitly should be passed with a command line argument. For example, the builders perform filter on build tags, so they need to know GOARCH and GOOS. The builder will add these to the environment before executing an SDK tool.
  • Any value that all builders should simply pass through to executed programs should be an environment variable.
  • There shouldn't be any overlap between these two categories, so env.go can continue doing what it did before.

@@ -24,13 +24,14 @@ import (
)

func install_stdlib(goenv *GoEnv, target string, args []string) error {
if goenv.tags != "" {
args = append(args, "-tags", goenv.tags)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mentioned ios in the description. I wonder if there's a way we can set that one automatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment the only way I found to reliably do it is by using ctx.fragments.cpp.target_gnu_system_name.

Here is the gist of the code, more or less (I plan to submit this later on):

PLATFORMS = {
    'armv7-apple-ios': apple_common.platform.ios_device,
    'arm64-apple-ios': apple_common.platform.ios_device,
    'i386-apple-ios': apple_common.platform.ios_simulator,
    'x86_64-apple-ios': apple_common.platform.ios_simulator,
}

def apple_ensure_options(ctx, env, tags, compiler_options, linker_options):
    system_name = ctx.fragments.cpp.target_gnu_system_name
    platform = PLATFORMS.get(system_name)
    if platform == None:
        return
    if system_name.endswith("-ios"):
        tags.append("ios") # needed for stdlib building
    if platform in [apple_common.platform.ios_device, apple_common.platform.ios_simulator]:
        min_version = _apple_version_min(platform, "6.1")
        compiler_options.append(min_version)
        linker_options.append(min_version)
    xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
    env.update(apple_common.target_apple_env(xcode_config, platform))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you can see also, this method modifies the environment, and in this case to tell the compiler which SDK to use (iPhoneOS, iPhoneSimulator).

For instance:

    APPLE_SDK_PLATFORM=iPhoneOS
    APPLE_SDK_VERSION_OVERRIDE=11.2
    XCODE_VERSION_OVERRIDE=9.2.0

These also need to be set at stdlib bootstrapping.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explaining. That makes more sense now.

@steeve
Copy link
Contributor Author

steeve commented Feb 22, 2018

thanks for the comments! i'll be updating it when I get the chance

@steeve
Copy link
Contributor Author

steeve commented Feb 24, 2018

I've updated the PR with the gotags suggestions 99f11a3.

I have all the tests passing. I fixed them with e42f021

@steeve
Copy link
Contributor Author

steeve commented Feb 24, 2018

Changed the go-bindata commit message to be closer to the ones here.

@steeve
Copy link
Contributor Author

steeve commented Feb 24, 2018

Added 940d41b which splits sources via a dict instead of using any + lists.
It improves splitting performance by about 6-7x. As this is kind of a hot path, hopefully it should yield noticeable improvements.

I benched it with this code: https://gist.github.com/steeve/56d3f107f24d8e67833f66ed3e06acdd

old: [8.00760793685913, 8.148405075073242, 8.099946975708008]
new: [1.3760578632354736, 1.4115018844604492, 1.4008851051330566]

@steeve
Copy link
Contributor Author

steeve commented Feb 24, 2018

Added two more commits that ensure the proper dependency chain for CGo and makes sure that all compiler options are used (some were missed when cross compiling)

@steeve
Copy link
Contributor Author

steeve commented Feb 27, 2018

I'm going to leave out the gopath commit for now so as to not block the PR with this. I'll open it on another PR.

@jayconrod
Copy link
Contributor

+1 to moving gopath to a separate PR. It will be easier to review and merge in pieces.

My only remaining comment is this one from d73858f. GitHub's code review system confuses me, and I think it got buried in a rebase somewhere. I'll copy it here:

Ok, I think I understand this better. I'm still concerned that it's prone to duplication. I don't think there's a situation where we actually need to merge flags in the same environment variable. Here's what I think we should do:

Any value that any builder needs to handle explicitly should be passed with a command line argument. For example, the builders perform filter on build tags, so they need to know GOARCH and GOOS. The builder will add these to the environment before executing an SDK tool.

Any value that all builders should simply pass through to executed programs should be an environment variable.

There shouldn't be any overlap between these two categories, so env.go can continue doing what it did before.

@steeve
Copy link
Contributor Author

steeve commented Feb 27, 2018

To be clear, what you're advising is that cgo_ldflags should be set specifically in the case of the stdlib bootstrap (it is set via a env now). SGTM

@jayconrod
Copy link
Contributor

My concern was about that we shouldn't do environment merging in env.go. It would be better to either set an environment variable to be passed through without modification to the toolchain, or to provide a command line argument to the builders (that maybe gets turned into an environment variable) but not both.

I guess CGO_LDFLAGS / -ld_flag is actually both right now. That's something I'm not happy with, but there's no need to fix that in this PR.

@steeve
Copy link
Contributor Author

steeve commented Feb 27, 2018

I'm going to go with the -ld_flags from env.go (at least for stdlib.bzl) because, well, it's there and setting CGO_LDFLAGS from the rule doesn't really make sense actually, imho

@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

Ok so what I'm going to do is if there is a conflict between the old (os.Environ() and the new env.env()), then the new will take precedence.
Effectively working like dict.update()

@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

I've updated the branch with your suggestions in 840fda3 and 5cda48b, so far so good

@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

I've added 112739d for a very quick fix by disabling linking with pthreads on all darwins, not only amd64

zllak and others added 6 commits February 28, 2018 14:37
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

Also added aa59cc9 which ensures go-bindata doesn't use the file's modtime unless otherwise specified. This would make our builds no hermetic when using it.

@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

And rebased on master

Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

Added dc60119 to add some parameters and extra_args to the go-bindata rule

Signed-off-by: Steeve Morin <steeve.morin@gmail.com>
@steeve
Copy link
Contributor Author

steeve commented Feb 28, 2018

Added 31222ea which add the field_mask well known type to gogo remaps

Sorry I keep adding commits but I figure given their scopes that now is a good time to do it

@jayconrod
Copy link
Contributor

jayconrod commented Feb 28, 2018

Ok, I think everything looks good at this point. Thanks!

@jayconrod jayconrod merged commit 9527696 into bazel-contrib:master Feb 28, 2018
@zllak zllak deleted the fix/various branch February 28, 2018 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants