diff options
Diffstat (limited to 'CC')
-rw-r--r-- | CC/prebuilt/EXPRESSIONS | 186 | ||||
-rw-r--r-- | CC/prebuilt/RULES | 31 | ||||
-rwxr-xr-x | CC/prebuilt/read_pkgconfig.py | 75 |
3 files changed, 288 insertions, 4 deletions
diff --git a/CC/prebuilt/EXPRESSIONS b/CC/prebuilt/EXPRESSIONS index ca576f4..fc901d7 100644 --- a/CC/prebuilt/EXPRESSIONS +++ b/CC/prebuilt/EXPRESSIONS @@ -88,13 +88,16 @@ } , "prebuilt result": { "vars": - [ "name" + [ "ENV" + , "name" , "version" , "stage" , "cflags" , "ldflags" , "libs" , "hdrs" + , "config_reader" + , "pkg-configs" , "deps-fieldnames" ] , "imports": @@ -105,6 +108,9 @@ , "link-args-deps": ["./", "..", "link-args-deps"] , "run-libs-deps": ["./", "..", "run-libs-deps"] , "run-libs-args-deps": ["./", "..", "run-libs-args-deps"] + , "cflags-files-deps": ["./", "..", "cflags-files-deps"] + , "ldflags-files-deps": ["./", "..", "ldflags-files-deps"] + , "default-ENV": ["./", "..", "default-ENV"] } , "expression": { "type": "let*" @@ -225,6 +231,179 @@ } } ] + , [ "ENV" + , { "type": "map_union" + , "$1": + { "type": "++" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "default-ENV"} + , [ { "type": "var" + , "name": "ENV" + , "default": {"type": "empty_map"} + } + ] + ] + } + } + ] + , [ "main-pkg-config" + , { "type": "foldl" + , "range": {"type": "var", "name": "pkg-configs", "default": []} + , "start": null + , "accum_var": "name" + , "var": "config" + , "body": + { "type": "if" + , "cond": {"type": "var", "name": "name"} + , "then": {"type": "var", "name": "name"} + , "else": + { "type": "join" + , "$1": {"type": "keys", "$1": {"type": "var", "name": "config"}} + } + } + } + ] + , [ "reader-inputs" + , { "type": "to_subdir" + , "subdir": "lib" + , "$1": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "libs"} + , { "type": "to_subdir" + , "subdir": "pkgconfig" + , "flat": true + , "$1": + { "type": "map_union" + , "$1": {"type": "var", "name": "pkg-configs", "default": []} + } + } + ] + } + } + ] + , [ "cflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".cflags"]} + ] + , [ "cflags-file" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "pkg-configs"} + , "then": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "config_reader"} + , {"type": "var", "name": "reader-inputs"} + ] + } + , "cmd": + [ "./config_reader" + , {"type": "var", "name": "cflags-filename"} + , {"type": "var", "name": "main-pkg-config"} + ] + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "cflags-filename"}] + } + , "else": {"type": "empty_map"} + } + } + ] + , [ "cflags-files" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "cflags-files-deps"} + , {"type": "var", "name": "cflags-file"} + ] + } + ] + , [ "compile-args" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "compile-args"} + , { "type": "if" + , "cond": {"type": "var", "name": "cflags-file"} + , "then": + [ { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ ["@"] + , { "type": "keys" + , "$1": {"type": "var", "name": "cflags-file"} + } + ] + } + } + ] + } + ] + } + ] + , [ "ldflags-filename" + , {"type": "join", "$1": [{"type": "var", "name": "name"}, ".ldflags"]} + ] + , [ "ldflags-file" + , { "type": "to_subdir" + , "subdir": {"type": "var", "name": "stage"} + , "$1": + { "type": "if" + , "cond": {"type": "var", "name": "pkg-configs"} + , "then": + { "type": "ACTION" + , "inputs": + { "type": "map_union" + , "$1": + [ {"type": "var", "name": "config_reader"} + , {"type": "var", "name": "reader-inputs"} + ] + } + , "cmd": + [ "./config_reader" + , {"type": "var", "name": "ldflags-filename"} + , {"type": "var", "name": "main-pkg-config"} + ] + , "env": {"type": "var", "name": "ENV"} + , "outs": [{"type": "var", "name": "ldflags-filename"}] + } + , "else": {"type": "empty_map"} + } + } + ] + , [ "ldflags-files" + , { "type": "map_union" + , "$1": + [ {"type": "CALL_EXPRESSION", "name": "ldflags-files-deps"} + , {"type": "var", "name": "ldflags-file"} + ] + } + ] + , [ "run-libs-args" + , { "type": "++" + , "$1": + [ {"type": "var", "name": "run-libs-args"} + , { "type": "if" + , "cond": {"type": "var", "name": "ldflags-file"} + , "then": + [ { "type": "join" + , "$1": + { "type": "++" + , "$1": + [ ["@"] + , { "type": "keys" + , "$1": {"type": "var", "name": "ldflags-file"} + } + ] + } + } + ] + } + ] + } + ] , [ "package" , { "type": "let*" , "bindings": @@ -241,7 +420,10 @@ } ] ] - , "body": {"type": "env", "vars": ["name", "version"]} + , "body": + { "type": "env" + , "vars": ["name", "version", "cflags-files", "ldflags-files"] + } } ] ] diff --git a/CC/prebuilt/RULES b/CC/prebuilt/RULES index be2bacc..16f9f26 100644 --- a/CC/prebuilt/RULES +++ b/CC/prebuilt/RULES @@ -1,8 +1,13 @@ { "library": { "doc": ["A prebuilt C++ library"] - , "target_fields": ["lib", "hdrs", "deps"] + , "target_fields": ["lib", "hdrs", "deps", "pkg-config"] , "string_fields": ["name", "version", "stage", "defines", "cflags", "ldflags"] + , "implicit": + { "defaults": [["./", "..", "defaults"]] + , "config_reader": [["CC", "prebuilt/read_pkgconfig.py"]] + } + , "config_vars": ["ENV"] , "field_doc": { "name": [ "The name of the library (without leading \"lib\" or trailing file name" @@ -32,6 +37,13 @@ ["List of compile flags set for this target and its consumers."] , "ldflags": ["Additional linker flags (typically for linking system libraries)."] + , "pkg-config": + [ "Pkg-config file for optional infer of public cflags and ldflags. If" + , "multiple files are specified (e.g., one depends on the other), the" + , "first one is used as entry. Note that if this field is non-empty the" + , "tool \"pkg-config\" must be available in \"PATH\", which is taken" + , "from [\"CC\", \"defaults\"] or the \"ENV\" variable." + ] } , "artifacts_doc": [ "The actual library (libname.a or libname.so). Only static libraries are" @@ -67,7 +79,9 @@ ] } , "imports": - { "artifacts_list": ["./", "../..", "field_artifacts_list"] + { "artifacts": ["./", "../..", "field_artifacts"] + , "artifacts_list": ["./", "../..", "field_artifacts_list"] + , "stage_field": ["", "stage_singleton_field"] , "prebuilt result": "prebuilt result" } , "expression": @@ -112,6 +126,19 @@ , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} } ] + , [ "config_reader" + , { "type": "let*" + , "bindings": + [["fieldname", "config_reader"], ["location", "config_reader"]] + , "body": {"type": "CALL_EXPRESSION", "name": "stage_field"} + } + ] + , [ "pkg-configs" + , { "type": "let*" + , "bindings": [["fieldname", "pkg-config"]] + , "body": {"type": "CALL_EXPRESSION", "name": "artifacts_list"} + } + ] , ["deps-fieldnames", ["deps"]] ] , "body": {"type": "CALL_EXPRESSION", "name": "prebuilt result"} diff --git a/CC/prebuilt/read_pkgconfig.py b/CC/prebuilt/read_pkgconfig.py new file mode 100755 index 0000000..cb4154f --- /dev/null +++ b/CC/prebuilt/read_pkgconfig.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# Copyright 2023 Huawei Cloud Computing Technology Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import subprocess +import sys +from pathlib import Path + + +def run_pkgconfig(args: list[str], env: dict[str, str]) -> str: + result = subprocess.run(["pkg-config"] + args, env=env, capture_output=True) + if result.returncode != 0: + print(result.stderr.decode("utf-8"), file=sys.stderr) + exit(1) + return result.stdout.decode("utf-8").strip() + + +def read_ldflags(pkg: str, env: dict[str, str]) -> str: + def libname(filename: str) -> str: + return filename.split(".")[0] + + local_libs = { + libname(f) + for it in os.walk(".") for f in it[2] if f.startswith("lib") + } + + link_flags = run_pkgconfig(["--libs-only-l", pkg], env).split(" ") + + # deduplicate, keep right-most + seen: set[str] = set() + link_flags = [ + f for f in link_flags[::-1] if f not in seen and not seen.add(f) + ][::-1] + + def is_local(flag: str) -> bool: + if not flag.startswith("-l"): + return False + lib = libname(flag[3:]) if flag.startswith("-l:") else f"lib{flag[2:]}" + return lib in local_libs + + return " ".join([f for f in link_flags if not is_local(f)]) + + +def read_pkgconfig(): + if len(sys.argv) < 3: + print(f"usage: read_pkgconfig OUT_NAME PC_FILE") + exit(1) + + name = sys.argv[1] + pkg = Path(sys.argv[2]).stem + env = dict(os.environ, PKG_CONFIG_PATH="./lib/pkgconfig") + + if name.endswith(".cflags"): + data = run_pkgconfig(["--cflags-only-other", pkg], env) + else: + data = read_ldflags(pkg, env) + + with open(f"{name}", 'w') as f: + f.write(data) + + +if __name__ == "__main__": + read_pkgconfig() |