bazelbuild / platforms

Constraint values for specifying platforms and toolchains
Apache License 2.0
106 stars 70 forks source link

MacOS being detected as multiple OSes #61

Closed andrewkatson closed 5 months ago

andrewkatson commented 1 year ago

So I have a BUILD file that looks like this


package(default_visibility = ["//visibility:public"])

config_setting(
    name = "windows",
    constraint_values = [
        "@platforms//os:windows",
    ],
    visibility = ["//visibility:public"],
)

config_setting(
    name = "mac",
    constraint_values = [
        "@platforms//os:macos",
    ],
    visibility = ["//visibility:public"],
)

config_setting(
   name = "linux",
   constraint_values = [
      "@platforms//os:linux",
   ],
   visibility = ["//visibility:public"],
)

cc_library(
   name = "db_drivers",
   srcs = select({ 
      "windows": glob(["**/*.a"]),
      "mac": ["liblmdb/midl.c", "liblmdb/mdb.c"],
      "linux": glob(["**/*.a"]),
   }),
   hdrs = glob(["**/liblmdb/*.h"]),
)

This is meant to be an external repository that I am defining a rule for. But when I run bazel query on the path to the library I have that depends on this I get the following.

@db_drivers//:liblmdb/liblmdb.a
@db_drivers//:liblmdb/lmdb.h
@db_drivers//:liblmdb/mdb.c
@db_drivers//:liblmdb/midl.c
@db_drivers//:liblmdb/midl.h

As you can see it is running the glob that is picking up the .a file even though that should only happen on mac. When I remove the linux part of the select it works and I don't pull in the .a. What am I doing wrong here?

andrewkatson commented 1 year ago

I see this issue with other libraries too just FYI so it is not just this BUILD file. Like one I have a glob I only want to run on linux and a normal list on mac but instead the glob runs.

This is that BUILD file

package(default_visibility = ["//visibility:public"])

config_setting(
    name = "windows",
    constraint_values = [
        "@platforms//os:windows",
    ],
    visibility = ["//visibility:public"],
)

config_setting(
    name = "mac",
    constraint_values = [
        "@platforms//os:macos",
    ],
    visibility = ["//visibility:public"],
)

config_setting(
   name = "linux",
   constraint_values = [
      "@platforms//os:linux",
   ],
   visibility = ["//visibility:public"],
)

cc_library(
  name = "libnorm",
  srcs = select({
    "windows": glob(["**/*.a"]),
    "mac": ["build/libnorm.a"],
    "linux": glob(["**/*.a"]),
  }),
  hdrs = select({
    "windows": glob(["**/include/**/*.h"]),
    "mac": [
        "include/galois.h",
        "include/normApi.h",
        "include/normEncoder.h",
        "include/normEncoderMDP.h",
        "include/normEncoderRS16.h",
        "include/normEncoderRS8.h",
        "include/normFile.h",
        "include/normMessage.h",
        "include/normNode.h",
        "include/normObject.h",
        "include/normPostProcess.h",
        "include/normSegment.h",
        "include/normSession.h",
        "include/normSimAgent.h",
        "include/normVersion.h"
    ],
    "linux": glob(["**/include/**/*.h"]),
  }),
  includes = select({
    "windows": [],
    "mac": ["include"],
    "linux": [],
  })
)
andrewkatson commented 1 year ago

Also I read https://bazel.build/reference/be/functions#select and this should not be possible. But it definitely is.

andrewkatson commented 1 year ago

Oh and even more odd when I specify linux_x86_64 with @platforms//cpu:x86_64 instead of just linux I still get it being selected even though I am on the M2 macbook air which should be arm.

andrewkatson commented 1 year ago

Also only when I remove the windows and linux branches of the select statement do I only run the mac code. I must be doing something wrong here but I can't figure it out.

andrewkatson commented 1 year ago

I have also tried just using @platforms//os:specific_os inside of the select statement.

andrewkatson commented 1 year ago

I have tested this on Windows and Ubuntu and the select works as it would be expected to.

andrewkatson commented 1 year ago

Okay I added a select using the same exact config_setting rules to the bazel codebase tests to see if I could reproduce this.

https://github.com/bazelbuild/bazel

And it worked exactly as expected. So I must be doing something wrong or bazel uses its own version of bazel separate from the one I am using.

andrewkatson commented 1 year ago

Hmmm now I am more confused. I think what is happening is that during evaluation these things are being picked up but during compilation and runtime these extra bits are not picked up. Because when I add in files that won't compile as sources the build fails. If I remove them the build succeeds. In both cases the bazel query shows the broken file as a dependency.

keith commented 1 year ago

Every branch of the select is included in the output of query. If you'd like to see specifically what would happen on the current platform you can use aquery instead.

aiuto commented 1 year ago

+1 to what keith said. query gives all select branches, cquery, along with whatever flags you use to set CPU or target OS, will give you only the used branch.

Also, it's sort of wasteful to wrap the platform constraints, as you did with

config_setting(
    name = "mac",
    constraint_values = ["@platforms//os:macos",],
)

You can use "@platforms//os:macos" directly as select() keys.

And, finally, to give you better control over what you get, you should consider using platforms to target the actual environments you are building for.

That will put you in much better position to cross compile for another platform, lets say mac arm from mac x86, or even windows from linux using clang.

andrewkatson commented 1 year ago

Oh I see I knew I was doing something odd. Okay so when I try to build something with the second BUILD file as a dependency I get the following error. Where it seems like it is trying to execute the glob. I guess it is trying to evaluate it or something but it doesn't strike me as intended behavior.

 no such package '@libnorm//': error globbing [**/include/**/*.h] op=FILES: /private/var/tmp/_bazel_andrewkatson/68e86775b12d9adab2e45c6c1e0fc99b/external/libnorm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm/norp/norm (Too many levels of symbolic links) and referenced by '//src:general_import_tester'
ERROR: Analysis of target '//src:general_import_tester' failed; build aborted: Analysis failed

I tried doing os + cpu to stop this and it didn't work it still tries to evaluate all of the branches.

fmeum commented 10 months ago

glob is evaluated before select, so you can't prevent globs from being executed by wrapping them in a select.

andrewkatson commented 5 months ago

Thank you!