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

Minimal Bazel infrastructure (#415). #577

Merged
merged 7 commits into from
Mar 17, 2017

Conversation

htuch
Copy link
Member

@htuch htuch commented Mar 16, 2017

This patch introduces the minimal Bazel infrastructure required to build and execute utility_test,
as a step towards conversion of the cmake build system to Bazel (#415). The main contributions are:

  • Machinery for declaring Envoy C++ library and test targets (envoy_cc_library, envoy_cc_test).

  • External dependency management that works both inside the Docker CI environment (using prebuilts)
    and with developer-local dependency fetch/build (based on Add Bazel support #416).

  • Handling of the implicit dependencies that are today sourced via prebuilts.

  • Simple example of building and running a unit test with only its dependencies built. With the
    cmake system, we would need to build all of Envoy and all tests to run utility_test. E.g.

    blaze test //test/common/common:utility_test

This is not intended to be used by anyone other than those working with the Bazel conversion at this
point. The plan is to add "ci/do_ci.sh bazel.debug" as a Travis target to ensure we don't bit rot.

This patch introduces the minimal Bazel infrastructure required to build and execute utility_test,
as a step towards conversion of the cmake build system to Bazel (envoyproxy#415). The main contributions are:

* Machinery for declaring Envoy C++ library and test targets (envoy_cc_library, envoy_cc_test).

* External dependency management that works both inside the Docker CI environment (using prebuilts)
  and with developer-local dependency fetch/build (based on envoyproxy#416).

* Handling of the implicit dependencies that are today sourced via prebuilts.

* Simple example of building and running a unit test with only its dependencies built. With the
  cmake system, we would need to build all of Envoy and all tests to run utility_test. E.g.

  blaze test //test/common/common:utility_test

This is not intended to be used by anyone other than those working with the Bazel conversion at this
point. The plan is to add "ci/do_ci.sh bazel.debug" as a Travis target to ensure we don't bit rot.
@htuch
Copy link
Member Author

htuch commented Mar 16, 2017

return "//external:%s" % dep

ENVOY_COPTS = [
"-ggdb3", "-fno-omit-frame-pointer", "-Wall", "-Wextra", "-Werror",
Copy link
Member

Choose a reason for hiding this comment

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

-ggdb3 shouldn't be enforced here, you can include it in .bazelrc (but only for specific config). bazel has -c flag to control fastbuild vs debug (dbg) vs release (opt)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm wondering where this would go in the repository. Let's say we do want our own standard set of additions for fastbuild/opt/debug, such as -ggdb3. Would we put this in $(ENVOY_SRC)/.bazelrc? If we put it here, my reading of the docs is that ~/.blazerc is then ignored. This would be bad as we disallow user configurability.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, I see, we have tools/bazel.rc to work with, great.

"-ggdb3", "-fno-omit-frame-pointer", "-Wall", "-Wextra", "-Werror",
"-Wnon-virtual-dtor", "-Woverloaded-virtual", "-Wold-style-cast",
"-std=c++0x", "-includesource/precompiled/precompiled.h",
"-isystem", "include", "-isystem", "source"
Copy link
Member

Choose a reason for hiding this comment

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

iquote? I don't see where we use <> to include from those directories.

"-isystem", "include", "-isystem", "source"
]

ENVOY_LINKOPTS = ["-static-libstdc++", "-static-libgcc"]
Copy link
Member

Choose a reason for hiding this comment

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

unused?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I originally was thinking about envoy_cc_binary, but we're aways from that.

ci/do_ci.sh Outdated
echo "Building..."
export CC=gcc-4.9
export CXX=g++-4.9
TEST_TMPDIR=/source/build USER=bazel bazel build --strategy=CppCompile=standalone \
Copy link
Member

Choose a reason for hiding this comment

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

use --batch to run bazel inside docker (no starting/shutting down server). Maybe worth to try to push those common bazel options in ci to a bazelrc file inside the docker image, so they don't repeatedly appears in the script.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've switched to --batch by default and cleaned up the duplication (bazelrc is probably a bit overkill so just refactored).

@mattklein123
Copy link
Member

@htuch FYI @lyft/network-team has no capability to review this right now. Please just get a +1 from @lizan and @PiotrSikora and I will merge.

@@ -2,7 +2,5 @@

#include "precompiled/precompiled.h"

#include "test/test_common/printers.h"
Copy link
Member

Choose a reason for hiding this comment

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

This is required to have pretty printing work correctly. It will compile but won't actually pretty print without it. Any reason to remove?

Copy link
Member Author

@htuch htuch Mar 16, 2017

Choose a reason for hiding this comment

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

Things that are in precompiled are depended upon by the envoy_cc_library rule, so it isn't possible to have them built using this rule. printers.cc actually depends on files such as common/buffer/buffer_impl.h, which is basically arbitrary implementation files. It's possible I could split the dependency at the header/source file level, with two distinct targets to resolve this, but I couldn't find any references to the symbols in the tree and thought it was stale.

Who uses the pretty printers? Is this GTest?

Copy link
Member Author

Choose a reason for hiding this comment

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

ENVOY_COPTS = [
"-fno-omit-frame-pointer", "-Wall", "-Wextra", "-Werror", "-Wnon-virtual-dtor",
"-Woverloaded-virtual", "-Wold-style-cast", "-std=c++0x",
"-includesource/precompiled/precompiled.h", "-iquote", "include", "-iquote", "source"
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a big fan of mixing compiler flags and includes, maybe just move them to envoy_cc_library?

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean in the includes attribute in envoy_cc_library? I tried that first time around, but since the target is relative to the package, it can't reference the build root. E.g. if the target being defined is in source/common/common, it can only specify includes in the cc_library that are a subdirectory of source/common/common.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, that what I've meant... But it indeed wouldn't work with BUILD files in subdirectories.

#

cc_library(
name = "googletest",
Copy link
Contributor

Choose a reason for hiding this comment

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

This by no means should block this PR, but I've seen this enough times by now, that maybe we should upstream this BUILD file to google/googletest?

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed. Was this from Istio originally? Does @lizan want to do this? If nobody owns it I can add it to my backlog.

Copy link
Contributor

Choose a reason for hiding this comment

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

It came from NGINX-based ESP. I believe Martin wrote this, so it's (c) Google and can be released under different license, if that's why you're asking. I don't believe anybody "owns" it right now, so please add it to your backlog. Thanks!

ci/WORKSPACE Outdated
@@ -0,0 +1,9 @@
bind(
name = "googletest_main",
actual = "//ci/prebuilt:googletest_main"
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: missing comma at the end.

ci/WORKSPACE Outdated

bind(
name = "spdlog",
actual = "//ci/prebuilt:spdlog"
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: missing comma at the end.


cc_library(
name = "googletest_main",
hdrs = glob([
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: hdrs should be listed after srcs.


def spdlog_repositories():
BUILD = """
package(default_visibility=["//visibility:public"])
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: missing surrounding spaces around =.

"include/**/*.h",
"include/**/*.cc",
]),
strip_include_prefix = "include"
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: missing comma at the end.

remote = "https://github.com/gabime/spdlog.git",
# v0.11.0 release
commit = "1f1f6a5f3b424203a429e9cb78e6548037adefa8",
build_file_content = BUILD,)
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: build_file_content should be listed before commit and remote.


native.new_git_repository(
name = "spdlog_git",
remote = "https://github.com/gabime/spdlog.git",
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: remote should be listed after commit.

def envoy_external_dep_path(dep):
return "//external:%s" % dep

ENVOY_COPTS = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: one flag per line.

Copy link
Contributor

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

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

Also, maybe consider moving bazel to tools subdirectory? We'll most likely need to create tools/bazel.rc anyway, so this way it wouldn't be spread out too much.

@@ -0,0 +1,13 @@
load("//bazel:repositories.bzl", "envoy_dependencies")

Copy link
Contributor

Choose a reason for hiding this comment

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

Add workspace(name = "envoy").

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, please add it at the top (before load()).

Copy link
Member Author

Choose a reason for hiding this comment

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

Turns out that if you move bazel to tools/bazel, Bazel tries to invoke the directory as a binary. I'm guessing that similar to the special nature of tools/bazel.rc, Bazel looks in tools/bazel for another bazel binary to reinvoke?!

Copy link
Contributor

Choose a reason for hiding this comment

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

Ouch! That's definitely unexpected... Nevermind, then!

def envoy_external_dep_path(dep):
return "//external:%s" % dep

ENVOY_COPTS = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: consider moving this at the top, otherwise it's intermixed with def ....

# The build rules below for external dependencies build rules are maintained
# on a best effort basis. The rules are provided for developer convenience. For production builds,
# we recommend building the libraries according to their canonical build systems and expressing the
# dependencies in a manner similar to ci/WORKSPACE.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: this paragraph is unevenly wrapped (first line @ 80, rest @ 100?).

native.cc_test(
name = name,
srcs = srcs,
deps = deps + ["//source/precompiled:precompiled_includes",
Copy link
Contributor

Choose a reason for hiding this comment

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

Style: consider splitting brackets from multiline lists (as in other places), i.e.:

[
    "//source/precompiled:precompiled_includes",
    "//test/precompiled:precompiled_includes",
]

and remember to add comma after last element.

Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: deps go at the end.

name = name,
srcs = srcs,
hdrs = hdrs + public_hdrs,
deps = deps + [envoy_external_dep_path(dep) for dep in external_deps] +
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: deps go at the end.

deps = deps + ["//source/precompiled:precompiled_includes",
"//test/precompiled:precompiled_includes"],
copts = ENVOY_COPTS + ["-includetest/precompiled/precompiled_test.h"],
linkopts = ["-pthread"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: missing comma at the end.

"googletest/src/*.cc",
"googletest/src/*.h",
"googlemock/src/*.cc",
]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Style: glob([]) should be sorted alphabetically, so everything from googlemock/ should go before googletest/.

hdrs = glob([
"include/**/*.h",
"include/**/*.cc",
]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Style: please sort this alphabetically.

hdrs = glob([
"thirdparty/spdlog-0.11.0/include/**/*.h",
"thirdparty/spdlog-0.11.0/include/**/*.cc",
]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Style: please sort this alphabetically.

hdrs = ["utility.h"],
deps = [
"//include/envoy/common:time_includes",
],
Copy link
Contributor

Choose a reason for hiding this comment

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

Style: consider consolidating single-element list into one line (like everywhere else).

hdrs = [],
external_deps = [],
deps = [],
copts = []):
Copy link
Member

Choose a reason for hiding this comment

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

you may want a **kwargs here to catch everything else that you don't touch and pass to cc_library (e.g. visibility, defines)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm trying to use the grpc trick of using envoy_cc_library as an indirect to facilitate later generation of cmake (or other build system) if needed. The idea I think is to constrain as much as possible what we do with the rule, so it wouldn't work as well to allow the target to make arbitrary use of cc_library features (e.g. strip_include_prefix) that might not work in other build systems.

Copy link
Member

Choose a reason for hiding this comment

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

Yes I understand that concept, but visibility is bazel specific concept that you will need unless you make all target public. Also I am pretty sure you will need alwayslink later :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added visibility (which can be stripped by other build systems as they don't use this information) and alwayslink.

I'm not sure how we'll end up using visibility - it's useful for hiding things that are package local and in theory it could be used to enforce some good practices with the source/ impls (forcing folks to depend only on abstract interfaces), but its main use IMHO is for very large monolithic code bases where you don't want completely unrelated projects forming dependencies against each others implementations which aren't subject to versioning or stable interfaces.

# Envoy C++ test targets should be specified with this function.
def envoy_cc_test(name,
srcs = [],
deps = []):
Copy link
Member

Choose a reason for hiding this comment

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

ditto

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

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

LGTM

srcs = srcs,
hdrs = hdrs + public_hdrs,
copts = ENVOY_COPTS + copts,
alwayslink = alwayslink,
Copy link
Contributor

Choose a reason for hiding this comment

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

Buildifier: alwayslink should be at the end.


def googletest_repositories():
BUILD = """
# Copyright 2016 Google Inc. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the only file ("generated" or not) that has the copyright. We should either drop it here (we can, since it's ours) or include in every BUILD file.

FWIW, OSPO usually requires copyright / license header in every single file, but it looks that's not the case in Envoy.

Copy link
Contributor

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

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

LGTM

@mattklein123 mattklein123 merged commit 72e88af into envoyproxy:master Mar 17, 2017
@htuch htuch deleted the bazel-minimal branch March 31, 2017 16:31
lambdai pushed a commit to lambdai/envoy-dai that referenced this pull request Jul 21, 2020
jpsim pushed a commit that referenced this pull request Nov 28, 2022
Makes several updates to our podspec in order to fix CocoaPods integration with v0.2.0:

- Link `resolv.9` and `c++` which is being done with Bazel today
- Link `SystemConfiguration` which is being done with Bazel today
- Specify Swift version and platform version
- Specify `source_files` **with an empty `.swift` file** in order to ensure that Swift libraries are linked when building (i.e., `swiftFoundation`)

**Important notes:**
Releasing new versions of the pod requires the following manual changes:
- Unzipping `envoy_ios_framework.zip`
- Renaming the directory to `envoy_ios_cocoapods`
- Creating an empty file at `envoy_ios_cocoapods/Envoy.framework/Swift/Empty.swift`. This forces CocoaPods to link Swift libraries as necessary. We worked around this in Bazel similarly in the past [here](envoyproxy/envoy-mobile@b8216e4#diff-6dc94efb18b54c46a32898ba3a5a0756R15)
- Copying the repo's `LICENSE` file and placing it at `envoy_ios_cocoapods/LICENSE`
- Re-zipping `envoy_ios_cocoapods` and uploading `envoy_ios_cocoapods.zip`

In the future, we should see if this can be simplified or at the very least add a script that uploads this artifact with each commit to master just like we do with other artifacts. This is being tracked in envoyproxy/envoy-mobile#578.

Note: There is a similar problem reported in CocoaPods that requires this empty Swift file workaround: CocoaPods/CocoaPods#8649.

I tested this PR by using this podspec for building an app against Envoy Mobile with CocoaPods. This spec is currently published as v0.2.0.

Signed-off-by: Michael Rebello <[email protected]>
Signed-off-by: JP Simard <[email protected]>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
Makes several updates to our podspec in order to fix CocoaPods integration with v0.2.0:

- Link `resolv.9` and `c++` which is being done with Bazel today
- Link `SystemConfiguration` which is being done with Bazel today
- Specify Swift version and platform version
- Specify `source_files` **with an empty `.swift` file** in order to ensure that Swift libraries are linked when building (i.e., `swiftFoundation`)

**Important notes:**
Releasing new versions of the pod requires the following manual changes:
- Unzipping `envoy_ios_framework.zip`
- Renaming the directory to `envoy_ios_cocoapods`
- Creating an empty file at `envoy_ios_cocoapods/Envoy.framework/Swift/Empty.swift`. This forces CocoaPods to link Swift libraries as necessary. We worked around this in Bazel similarly in the past [here](envoyproxy/envoy-mobile@b8216e4#diff-6dc94efb18b54c46a32898ba3a5a0756R15)
- Copying the repo's `LICENSE` file and placing it at `envoy_ios_cocoapods/LICENSE`
- Re-zipping `envoy_ios_cocoapods` and uploading `envoy_ios_cocoapods.zip`

In the future, we should see if this can be simplified or at the very least add a script that uploads this artifact with each commit to master just like we do with other artifacts. This is being tracked in envoyproxy/envoy-mobile#578.

Note: There is a similar problem reported in CocoaPods that requires this empty Swift file workaround: CocoaPods/CocoaPods#8649.

I tested this PR by using this podspec for building an app against Envoy Mobile with CocoaPods. This spec is currently published as v0.2.0.

Signed-off-by: Michael Rebello <[email protected]>
Signed-off-by: JP Simard <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants