From 8c13dbb7d1d47380653e24e2ac50ace91fa49267 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Wed, 15 Feb 2023 15:56:26 -0600 Subject: [PATCH] Update bazel files Signed-off-by: Michael Carroll --- BUILD.bazel | 151 +++++++++++++++++++++++++++++++++++ include/sdf/config.hh.in | 5 +- sdf/embedSdf.py | 167 +++++++++++++++++++++++++-------------- src/SDF.cc | 54 ++++++------- test/BUILD.bazel | 57 +++++++++++++ 5 files changed, 344 insertions(+), 90 deletions(-) create mode 100644 BUILD.bazel create mode 100644 test/BUILD.bazel diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..31c9166c1 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,151 @@ +load( + "@gz//bazel/skylark:build_defs.bzl", + "GZ_FEATURES", + "GZ_ROOT", + "GZ_VISIBILITY", + "gz_configure_header", + "gz_export_header", + "gz_include_header", +) +load("@gz//bazel/skylark:gz_py.bzl", "gz_py_binary") + +package( + default_visibility = GZ_VISIBILITY, + features = GZ_FEATURES, +) + +licenses(["notice"]) # Apache-2.0 + +exports_files(["LICENSE"]) + +gz_configure_header( + name = "config", + src = "include/sdf/config.hh.in", + cmakelists = ["CMakeLists.txt"], + defines = { + "CMAKE_INSTALL_FULL_DATAROOTDIR": "", + }, + package = "sdformat", +) + +gz_py_binary( + name = "embed_sdf", + srcs = ["sdf/embedSdf.py"], +) + +genrule( + name = "embed_sdf_genrule", + srcs = glob([ + "sdf/**/*.sdf", + "sdf/**/*.convert", + ]), + outs = ["EmbeddedSdf.cc"], + cmd = "$(execpath :embed_sdf) --output-file $@ --sdf-root ./sdformat/ --input-files $(SRCS)", # noqa + tools = [":embed_sdf"], +) + +public_headers_no_gen = glob([ + "include/sdf/*.h", + "include/sdf/*.hh", +]) + +private_headers = glob(["src/*.hh"]) + +sources = glob( + ["src/*.cc"], + exclude = [ + "src/*_TEST.cc", + "src/gz.cc", + ], +) + +gz_export_header( + name = "include/sdf/Export.hh", + export_base = "GZ_SDFORMAT", + lib_name = "sdf", + visibility = ["//visibility:private"], +) + +gz_include_header( + name = "sdformat_hh_genrule", + out = "include/sdformat.hh", + hdrs = public_headers_no_gen + [ + "include/sdf/config.hh", + "include/sdf/Export.hh", + ], +) + +public_headers = public_headers_no_gen + [ + "include/sdf/Export.hh", + "include/sdf/config.hh", + "include/sdformat.hh", +] + +cc_library( + name = "urdf", + srcs = [ + "src/urdf/urdf_parser/joint.cpp", + "src/urdf/urdf_parser/link.cpp", + "src/urdf/urdf_parser/model.cpp", + "src/urdf/urdf_parser/pose.cpp", + "src/urdf/urdf_parser/twist.cpp", + "src/urdf/urdf_parser/urdf_model_state.cpp", + "src/urdf/urdf_parser/urdf_sensor.cpp", + "src/urdf/urdf_parser/world.cpp", + ], + hdrs = glob( + ["src/urdf/**/*.h"], + ), + copts = ["-Wno-unknown-pragmas"], + includes = ["src/urdf"], + deps = [ + "@tinyxml2", + ], +) + +cc_library( + name = "sdformat", + srcs = sources + private_headers + ["EmbeddedSdf.cc"], + hdrs = public_headers, + includes = [ + "include", + "src", + ], + defines = [ + 'SDF_SHARE_PATH=\\".\\"', + 'SDF_VERSION_PATH=\\"sdformat\\"', + ], + deps = [ + ":urdf", + GZ_ROOT + "math", + GZ_ROOT + "utils", + "@tinyxml2", + ], +) + +test_sources = glob( + ["src/*_TEST.cc"], + exclude = ["src/gz_TEST.cc"], +) + +[cc_test( + name = src.replace("/", "_").replace(".cc", "").replace("src_", ""), + srcs = [src], + data = [ + "sdf", + GZ_ROOT + "sdformat/test:integration", + GZ_ROOT + "sdformat/test:sdf", + ], + env = { + "GZ_BAZEL": "1", + "GZ_BAZEL_PATH": "sdformat", + }, + deps = [ + ":sdformat", + GZ_ROOT + "sdformat/test:test_utils", + "@gtest", + "@gtest//:gtest_main", + ], +) for src in test_sources] + +exports_files(["sdf"]) diff --git a/include/sdf/config.hh.in b/include/sdf/config.hh.in index e39759336..7b128ebad 100644 --- a/include/sdf/config.hh.in +++ b/include/sdf/config.hh.in @@ -53,9 +53,6 @@ #ifndef SDF_VERSION_PATH #define SDF_VERSION_PATH "${CMAKE_INSTALL_FULL_DATAROOTDIR}/sdformat${SDF_MAJOR_VERSION}/${SDF_PKG_VERSION}" -#endif - -static constexpr const char * kSdfSharePath = SDF_SHARE_PATH; -static constexpr const char * kSdfVersionPath = SDF_VERSION_PATH; +#endif #endif // #ifndef SDF_CONFIG_HH_ diff --git a/sdf/embedSdf.py b/sdf/embedSdf.py index b89607fa6..ab367d672 100644 --- a/sdf/embedSdf.py +++ b/sdf/embedSdf.py @@ -1,29 +1,49 @@ #!/usr/bin/env python3 +""" +Script for generating a C++ file that contains the content from all SDF files +""" + +from typing import List, Optional + +import argparse import inspect -from pathlib import Path, PurePosixPath +import sys +from pathlib import Path -""""Script for generating a C++ file that contains the content from all SDF files""" # The list of supported SDF specification versions. This will let us drop # versions without removing the directories. -SUPPORTED_SDF_VERSIONS = ['1.10', '1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3', '1.2'] +SUPPORTED_SDF_VERSIONS = [ + "1.10", + "1.9", + "1.8", + "1.7", + "1.6", + "1.5", + "1.4", + "1.3", + "1.2", +] # The list of supported SDF conversions. This list includes versions that # a user can convert an existing SDF version to. -SUPPORTED_SDF_CONVERSIONS = ['1.10', '1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3'] +SUPPORTED_SDF_CONVERSIONS = ["1.10", "1.9", "1.8", "1.7", "1.6", "1.5", "1.4", "1.3"] # whitespace indentation for C++ code -INDENTATION = ' ' +INDENTATION = " " + # newline character -NEWLINE = '\n' +NEWLINE = "\n" + def get_copyright_notice() -> str: """ - Provides the copyrigt notice for the C++ file + Provides the copyright notice for the C++ file :returns: copyright notice """ - res = inspect.cleandoc(""" + res = inspect.cleandoc( + """ /* * Copyright 2022 Open Source Robotics Foundation * @@ -40,8 +60,9 @@ def get_copyright_notice() -> str: * limitations under the License. * */ - """) - return res + 2*NEWLINE + """ + ) + return res + 2 * NEWLINE def get_file_header_prolog() -> str: @@ -50,7 +71,8 @@ def get_file_header_prolog() -> str: :returns: prolog of the C++ file """ - res = inspect.cleandoc(""" + res = inspect.cleandoc( + """ #include "EmbeddedSdf.hh" namespace sdf @@ -61,60 +83,39 @@ def get_file_header_prolog() -> str: const std::map &GetEmbeddedSdf() { static const std::map result { - """) + """ + ) return res + NEWLINE def embed_sdf_content(arg_path: str, arg_file_content: str) -> str: """ - Generates a string pair with the folder and filename as well as the content of the file + Generates a string pair with the folder and filename + as well as the content of the file :param arg_path: Foldername and filename of the SDF :param arg_file_content: Content of the provided file :returns: raw string literal mapping pair for the std::map """ res = [] - res.append('// NOLINT') - res.append('{') + res.append("// NOLINT") + res.append("{") res.append(f'"{arg_path}",') res.append('R"__sdf_literal__(') - res.append(f'{arg_file_content}') + res.append(f"{arg_file_content}") res.append(')__sdf_literal__"') - res.append('},') - res.append('') + res.append("}") return NEWLINE.join(res) -def get_map_content(arg_pathlist: Path) -> str: - """ - Generates a string pair with the folder and filename as well as the content - of the file in ascending order - - :param arg_pathlist: Foldername and all filenames inside it - :returns: mapping pairs for the std::map - """ - map_str = '' - files = [] - for path in arg_pathlist: - # dir separator is hardcoded to '/' in C++ mapping - posix_path = PurePosixPath(path) - files.append(str(posix_path)) - # get ascending order - files.sort() - for file in files: - with Path(file).open() as f: - content = f.read() - map_str += embed_sdf_content(file, content) - return map_str - - def get_file_header_epilog() -> str: """ Provides the return statement and the closing brackets of the C++ file :returns: epilog of the C++ file """ - res = inspect.cleandoc(""" + res = inspect.cleandoc( + """ }; return result; @@ -123,29 +124,79 @@ def get_file_header_epilog() -> str: } } // namespace sdf - """) + """ + ) return NEWLINE + res -if __name__ == "__main__": - copyright = get_copyright_notice() +def write_output(file_content: str, output_filename: str) -> None: + """ + Print the content of the EmbeddedSdf.cc to a file + """ + copyright_notice = get_copyright_notice() prolog = get_file_header_prolog() + epilog = get_file_header_epilog() + output_content = copyright_notice + prolog + file_content + epilog - map_str = "" - for sdf_version in SUPPORTED_SDF_VERSIONS: - pathlist = Path(sdf_version).glob('*.sdf') - map_str += get_map_content(pathlist) + with open(output_filename, "w", encoding="utf8") as output_file: + output_file.write(output_content) - for sdf_conversion in SUPPORTED_SDF_CONVERSIONS: - pathlist = Path(sdf_conversion).glob('*.convert') - map_str += get_map_content(pathlist) - # remove the last comma - map_str = map_str[:-2] +def collect_file_locations() -> List[Path]: + paths: List[Path] = [] - epilog = get_file_header_epilog() + for sdf_version in SUPPORTED_SDF_VERSIONS: + paths.extend(Path(sdf_version).glob("*.sdf")) + for sdf_conversion in SUPPORTED_SDF_CONVERSIONS: + paths.extend(Path(sdf_conversion).glob("*.convert")) + return paths + + +def generate_map_content(paths: List[Path], relative_to: Optional[str] = None) -> str: + ''' + Generate the EmbeddedSdf.cc content + ''' + content = [] + for path in paths: + with open(path, "r", encoding="utf8") as input_sdf: + file_content = input_sdf.read() + + # Strip relative path if requested + if relative_to: + path = path.relative_to(relative_to) + content.append(embed_sdf_content(str(path), file_content)) + return ",".join(content) + + +def main(args=None) -> int: + ''' + Main entrypoint + ''' + if args is None: + args = sys.argv[1:] + + parser = argparse.ArgumentParser() + + parser.add_argument( + "--sdf-root", + help="Directory containing sdf description files for each version", + ) + parser.add_argument( + "--input-files", nargs="*", help="List of input files to be embedded" + ) + parser.add_argument( + "--output-file", help="File to output embeddedsdf.cc content to" + ) + + args = parser.parse_args(args) + if not args.input_files or len(args.input_files) == 0: + paths = collect_file_locations() + else: + paths = [Path(f) for f in args.input_files] + content = generate_map_content(paths, args.sdf_root) + write_output(content, args.output_file) + return 0 - output = copyright + prolog + map_str + epilog - # output to stdin so that CMake can read it and create the appropriate file - print(output) +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/SDF.cc b/src/SDF.cc index be4852ae8..1166c8855 100644 --- a/src/SDF.cc +++ b/src/SDF.cc @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -43,18 +44,6 @@ inline namespace SDF_VERSION_NAMESPACE // returns the version string when possible. std::string SDF::version = SDF_VERSION; // NOLINT(runtime/string) -std::string sdfSharePath() -{ -#ifdef SDF_SHARE_PATH - if (std::string(SDF_SHARE_PATH) != "/") - return SDF_SHARE_PATH; - else - return ""; -#endif - return ""; -} - - ///////////////////////////////////////////////// void setFindCallback(std::function _cb) { @@ -109,27 +98,36 @@ std::string findFile(const std::string &_filename, bool _searchLocalPath, filename = filename.substr(idx + sep.length()); } - if (sdfSharePath() != "") + if (filename[0] == '/' && sdf::filesystem::exists(filename)) { - // Next check the install path. - std::string path = sdf::filesystem::append(sdfSharePath(), filename); - if (sdf::filesystem::exists(path)) - { - return path; - } + return filename; + } - // Next check the versioned install path. - path = sdf::filesystem::append(sdfSharePath(), - "sdformat" SDF_MAJOR_VERSION_STR, - sdf::SDF::Version(), filename); - if (sdf::filesystem::exists(path)) - { - return path; - } + + // Next check the install path. + std::string path = sdf::filesystem::append(SDF_SHARE_PATH, filename); + + std::cout << SDF_SHARE_PATH << std::endl; + std::cout << "Checking: " << path << std::endl; + + if (sdf::filesystem::exists(path)) + { + return path; + } + + + // Next check the versioned install path. + path = sdf::filesystem::append(SDF_SHARE_PATH, + "sdformat" SDF_MAJOR_VERSION_STR, + sdf::SDF::Version(), filename); + std::cout << "Checking: " << path << std::endl; + if (sdf::filesystem::exists(path)) + { + return path; } // Next check to see if the given file exists. - std::string path = filename; + path = filename; if (sdf::filesystem::exists(path)) { return path; diff --git a/test/BUILD.bazel b/test/BUILD.bazel new file mode 100644 index 000000000..2743e75f0 --- /dev/null +++ b/test/BUILD.bazel @@ -0,0 +1,57 @@ +load( + "@gz//bazel/skylark:build_defs.bzl", + "GZ_ROOT", + "cmake_configure_file", +) + +cmake_configure_file( + name = "config", + src = "test_config.hh.in", + out = "test_config.hh", + cmakelists = ["CMakeLists.txt"], + defines = [] +) + +cc_library( + name = "test_utils", + hdrs = ["test_utils.hh", "test_config.hh"], + includes = ["."], + visibility = ["//visibility:public"], +) + +integration_test_sources = glob( + ["integration/*.cc"], + exclude = [ + "integration/schema_test.cc", + "integration/element_memory_leak.cc", + ], +) + +[cc_test( + name = src.replace("/", "_").replace(".cc", "").replace("integration_", "INTEGRATION_"), + srcs = [ + src, + "integration/toml_parser.hh", + ], + data = [ + GZ_ROOT + "sdformat:sdf", + "integration", + "sdf", + ], + env = { + "GZ_BAZEL": "1", + "GZ_BAZEL_PATH": "sdformat", + }, + includes = ["integration"], + deps = [ + GZ_ROOT + "sdformat:sdformat", + ":test_utils", + "@gtest", + "@gtest//:gtest_main", + ], +) for src in integration_test_sources] + +exports_files([ + "sdf", + "integration", +])