Browse Source

Emit an includable CMake file that imports results from build-deps

default_compile_flags
vector-of-bool 3 years ago
parent
commit
c878e7a0c7
12 changed files with 127 additions and 2 deletions
  1. +69
    -0
      src/dds/build/builder.cpp
  2. +1
    -0
      src/dds/build/params.hpp
  3. +1
    -0
      src/dds/cli/cmd/build_deps.cpp
  4. +7
    -0
      src/dds/cli/options.cpp
  5. +2
    -0
      src/dds/cli/options.hpp
  6. +7
    -0
      tests/projects/simple-cmake/CMakeLists.txt
  7. +3
    -0
      tests/projects/simple-cmake/main.cpp
  8. +3
    -0
      tests/projects/simple/include/foo.hpp
  9. +5
    -0
      tests/projects/simple/src/foo.cpp
  10. +26
    -1
      tests/test_build_deps.py
  11. +1
    -1
      tools/Dockerfile.alpine
  12. +2
    -0
      tools/dds_ci/dds.py

+ 69
- 0
src/dds/build/builder.cpp View File

#include <dds/util/time.hpp> #include <dds/util/time.hpp>


#include <fansi/styled.hpp> #include <fansi/styled.hpp>
#include <fmt/ostream.h>


#include <array> #include <array>
#include <set> #include <set>
} }
} }


void write_lib_cmake(build_env_ref env,
std::ostream& out,
const package_plan& pkg,
const library_plan& lib) {
fmt::print(out, "# Library {}/{}\n", pkg.namespace_(), lib.name());
auto cmake_name = fmt::format("{}::{}", pkg.namespace_(), lib.name());
auto cm_kind = lib.archive_plan().has_value() ? "STATIC" : "INTERFACE";
fmt::print(
out,
"if(TARGET {0})\n"
" get_target_property(dds_imported {0} dds_IMPORTED)\n"
" if(NOT dds_imported)\n"
" message(WARNING [[A target \"{0}\" is already defined, and not by a dds import]])\n"
" endif()\n"
"else()\n",
cmake_name);
fmt::print(out,
" add_library({0} {1} IMPORTED GLOBAL)\n"
" set_property(TARGET {0} PROPERTY dds_IMPORTED TRUE)\n"
" set_property(TARGET {0} PROPERTY INTERFACE_INCLUDE_DIRECTORIES [[{2}]])\n",
cmake_name,
cm_kind,
lib.library_().public_include_dir().generic_string());
for (auto&& use : lib.uses()) {
fmt::print(out,
" set_property(TARGET {} APPEND PROPERTY INTERFACE_LINK_LIBRARIES {}::{})\n",
cmake_name,
use.namespace_,
use.name);
}
for (auto&& link : lib.links()) {
fmt::print(out,
" set_property(TARGET {} APPEND PROPERTY\n"
" INTERFACE_LINK_LIBRARIES $<LINK_ONLY:{}::{}>)\n",
cmake_name,
link.namespace_,
link.name);
}
if (auto& arc = lib.archive_plan()) {
fmt::print(out,
" set_property(TARGET {} PROPERTY IMPORTED_LOCATION [[{}]])\n",
cmake_name,
(env.output_root / arc->calc_archive_file_path(env.toolchain)).generic_string());
}
fmt::print(out, "endif()\n");
}

void write_cmake_pkg(build_env_ref env, std::ostream& out, const package_plan& pkg) {
fmt::print(out, "## Imports for {}\n", pkg.name());
for (auto& lib : pkg.libraries()) {
write_lib_cmake(env, out, pkg, lib);
}
fmt::print(out, "\n");
}

void write_cmake(build_env_ref env, const build_plan& plan, path_ref cmake_out) {
fs::create_directories(fs::absolute(cmake_out).parent_path());
auto out = open(cmake_out, std::ios::binary | std::ios::out);
out << "## This CMake file was generated by `dds build-deps`. DO NOT EDIT!\n\n";
for (const auto& pkg : plan.packages()) {
write_cmake_pkg(env, out, pkg);
}
}

template <typename Func> template <typename Func>
void with_build_plan(const build_params& params, void with_build_plan(const build_params& params,
const std::vector<sdist_target>& sdists, const std::vector<sdist_target>& sdists,
if (params.emit_lmi) { if (params.emit_lmi) {
write_lmi(env, plan, params.out_root, *params.emit_lmi); write_lmi(env, plan, params.out_root, *params.emit_lmi);
} }

if (params.emit_cmake) {
write_cmake(env, plan, *params.emit_cmake);
}
}); });
} }

+ 1
- 0
src/dds/build/params.hpp View File

fs::path out_root; fs::path out_root;
std::optional<fs::path> existing_lm_index; std::optional<fs::path> existing_lm_index;
std::optional<fs::path> emit_lmi; std::optional<fs::path> emit_lmi;
std::optional<fs::path> emit_cmake{};
dds::toolchain toolchain; dds::toolchain toolchain;
bool generate_compdb = true; bool generate_compdb = true;
int parallel_jobs = 0; int parallel_jobs = 0;

+ 1
- 0
src/dds/cli/cmd/build_deps.cpp View File

.out_root = opts.out_path.value_or(fs::current_path() / "_deps"), .out_root = opts.out_path.value_or(fs::current_path() / "_deps"),
.existing_lm_index = {}, .existing_lm_index = {},
.emit_lmi = opts.build.lm_index.value_or("INDEX.lmi"), .emit_lmi = opts.build.lm_index.value_or("INDEX.lmi"),
.emit_cmake = opts.build_deps.cmake_file,
.toolchain = opts.load_toolchain(), .toolchain = opts.load_toolchain(),
.parallel_jobs = opts.jobs, .parallel_jobs = opts.jobs,
}; };

+ 7
- 0
src/dds/cli/options.cpp View File

.can_repeat = true, .can_repeat = true,
.action = debate::push_back_onto(opts.build_deps.deps_files), .action = debate::push_back_onto(opts.build_deps.deps_files),
}); });
build_deps_cmd.add_argument({
.long_spellings = {"cmake"},
.help = "Generate a CMake file at the given path that will create import targets for "
"the dependencies",
.valname = "<file-path>",
.action = debate::put_into(opts.build_deps.cmake_file),
});
build_deps_cmd.add_argument({ build_deps_cmd.add_argument({
.help = "Dependency statement strings", .help = "Dependency statement strings",
.valname = "<dependency>", .valname = "<dependency>",

+ 2
- 0
src/dds/cli/options.hpp View File

std::vector<fs::path> deps_files; std::vector<fs::path> deps_files;
/// Dependency strings provided directly in the command-line /// Dependency strings provided directly in the command-line
std::vector<string> deps; std::vector<string> deps;
/// Path to a CMake import file to write
opt_path cmake_file;
} build_deps; } build_deps;


/** /**

+ 7
- 0
tests/projects/simple-cmake/CMakeLists.txt View File

cmake_minimum_required(VERSION 3.12)
project(TestProject)

include(${PROJECT_BINARY_DIR}/libraries.cmake)

add_executable(app main.cpp)
target_link_libraries(app PRIVATE test::foo)

+ 3
- 0
tests/projects/simple-cmake/main.cpp View File

#include <foo.hpp>

int main() { say_hello(); }

+ 3
- 0
tests/projects/simple/include/foo.hpp View File

#pragma once

extern void say_hello();

+ 5
- 0
tests/projects/simple/src/foo.cpp View File

#include <foo.hpp>

#include <iostream>

void say_hello() { std::cout << "Hello!\n"; }

+ 26
- 1
tests/test_build_deps.py View File



import pytest import pytest


from dds_ci.testing import RepoServer, Project
from dds_ci.testing import RepoServer, Project, ProjectOpener
from dds_ci import proc, toolchain


SIMPLE_CATALOG = { SIMPLE_CATALOG = {
"packages": { "packages": {
assert test_project.root.joinpath('_deps/_libman/neo-fun.lmp').is_file() assert test_project.root.joinpath('_deps/_libman/neo-fun.lmp').is_file()
assert test_project.root.joinpath('_deps/_libman/neo/fun.lml').is_file() assert test_project.root.joinpath('_deps/_libman/neo/fun.lml').is_file()
assert test_project.root.joinpath('INDEX.lmi').is_file() assert test_project.root.joinpath('INDEX.lmi').is_file()


def test_cmake_simple(project_opener: ProjectOpener) -> None:
proj = project_opener.open('projects/simple')
proj.dds.pkg_import(proj.root)

cm_proj_dir = project_opener.test_dir / 'projects/simple-cmake'
proj.build_root.mkdir(exist_ok=True, parents=True)
proj.dds.run(
[
'build-deps',
proj.dds.repo_dir_arg,
'foo@1.2.3',
('-t', ':gcc' if 'gcc' in toolchain.get_default_toolchain().name else ':msvc'),
f'--cmake=libraries.cmake',
],
cwd=proj.build_root,
)

try:
proc.check_run(['cmake', '-S', cm_proj_dir, '-B', proj.build_root])
except FileNotFoundError:
assert False, 'Running the integration tests requires a CMake executable'
proc.check_run(['cmake', '--build', proj.build_root])

+ 1
- 1
tools/Dockerfile.alpine View File



# Base build dependencies # Base build dependencies
RUN apk add "gcc=9.3.0-r2" "g++=9.3.0-r2" make python3 py3-pip \ RUN apk add "gcc=9.3.0-r2" "g++=9.3.0-r2" make python3 py3-pip \
git openssl-libs-static openssl-dev ccache lld curl python3-dev
git openssl-libs-static openssl-dev ccache lld curl python3-dev cmake


# We use version-qualified names for compiler executables # We use version-qualified names for compiler executables
RUN ln -s $(type -P gcc) /usr/local/bin/gcc-9 && \ RUN ln -s $(type -P gcc) /usr/local/bin/gcc-9 && \

+ 2
- 0
tools/dds_ci/dds.py View File

toolchain = toolchain or tc_mod.get_default_audit_toolchain() toolchain = toolchain or tc_mod.get_default_audit_toolchain()
self.run([ self.run([
'compile-file', 'compile-file',
self.catalog_path_arg,
self.repo_dir_arg,
paths, paths,
f'--toolchain={toolchain}', f'--toolchain={toolchain}',
f'{self.project_dir_flag}={project_dir}', f'{self.project_dir_flag}={project_dir}',

Loading…
Cancel
Save