Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/cppship/cmake/dependency_injector.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <ostream>

#include "cppship/core/dependency.h"
#include "cppship/core/manifest.h"
#include "cppship/util/class.h"

Expand All @@ -18,7 +19,22 @@ class DependencyInjector {

class CmakeDependencyInjector : public DependencyInjector {
public:
CmakeDependencyInjector(const fs::path& deps_dir, const std::vector<DeclaredDependency>& declared_deps,
const ResolvedDependencies& cppship_deps, const ResolvedDependencies& all_deps)
: mDepsDir(deps_dir)
, mDeclaredDeps(declared_deps)
, mCppshipDeps(cppship_deps)
, mAllDeps(all_deps)
{
}

void inject(std::ostream& out, const Manifest& manifest) override;

private:
fs::path mDepsDir;
std::vector<DeclaredDependency> mDeclaredDeps;
ResolvedDependencies mCppshipDeps;
ResolvedDependencies mAllDeps;
};

}
2 changes: 2 additions & 0 deletions include/cppship/cmake/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace cppship::cmake {

struct LibDesc {
std::string name;
std::optional<std::string> name_alias;
std::set<fs::path> include_dirs;
std::set<fs::path> sources;
std::vector<Dep> deps;
Expand All @@ -30,6 +31,7 @@ class CmakeLib {

private:
std::string mName;
std::optional<std::string> mNameAlias;
std::set<std::string> mIncludes;
std::set<std::string> mSources;
std::vector<Dep> mDeps;
Expand Down
20 changes: 20 additions & 0 deletions include/cppship/cmake/package_configurer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "cppship/core/dependency.h"
#include "cppship/util/fs.h"

#include <functional>

namespace cppship::cmake {

struct ConfigOptions {
fs::path deps_dir;
fs::path out_dir = deps_dir;
std::string cmake_deps_dir = "${CMAKE_SOURCE_DIR}/deps";
std::function<void(std::string&)> post_process;
};

void config_packages(
const ResolvedDependencies& cppship_deps, const ResolvedDependencies& all_deps, const ConfigOptions& options);

}
23 changes: 23 additions & 0 deletions include/cppship/core/dependency.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <map>
#include <string>
#include <string_view>
#include <variant>
#include <vector>

#include <toml.hpp>
Expand All @@ -11,6 +12,28 @@

namespace cppship {

struct ConanDep {
std::string version;
std::unordered_map<std::string, std::string> options;
};

struct GitDep {
std::string git;
std::string commit;
};

using DependencyDesc = std::variant<ConanDep, GitDep>;

struct DeclaredDependency {
std::string package;
std::vector<std::string> components;
DependencyDesc desc;

bool is_conan() const { return std::holds_alternative<ConanDep>(desc); }

bool is_git() const { return std::holds_alternative<GitDep>(desc); }
};

struct Dependency {
std::string package;
std::string cmake_package;
Expand Down
20 changes: 1 addition & 19 deletions include/cppship/core/manifest.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,16 @@
#include <string>
#include <string_view>
#include <unordered_map>
#include <variant>
#include <vector>

#include <fmt/format.h>

#include "cppship/core/dependency.h"
#include "cppship/core/profile.h"
#include "cppship/util/fs.h"

namespace cppship {

struct ConanDep {
std::string version;
std::unordered_map<std::string, std::string> options;
};

struct GitHeaderOnlyDep {
std::string git;
std::string commit;
};

using DependencyDesc = std::variant<ConanDep, GitHeaderOnlyDep>;

struct DeclaredDependency {
std::string package;
std::vector<std::string> components;
DependencyDesc desc;
};

enum class CxxStd { cxx11 = 11, cxx14 = 14, cxx17 = 17, cxx20 = 20, cxx23 = 23 };

inline constexpr auto format_as(CxxStd std) { return fmt::underlying(std); }
Expand Down
51 changes: 26 additions & 25 deletions lib/cmake/dependency_injector.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#include "cppship/cmake/dependency_injector.h"
#include "cppship/cmake/package_configurer.h"
#include "cppship/util/fs.h"
#include "cppship/util/io.h"

#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <fmt/format.h>
#include <fmt/os.h>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/concat.hpp>
#include <range/v3/view/filter.hpp>

using namespace cppship;
Expand Down Expand Up @@ -258,16 +259,19 @@ void inject_conan_deps(std::ostream& out)
out << "include(cmake/conan.cmake)\n";
}

void inject_git_deps(std::ostream& out, const std::vector<DeclaredDependency>& deps)
void inject_git_deps(std::ostream& out, const fs::path& deps_dir, const std::vector<DeclaredDependency>& deps,
const ResolvedDependencies& cppship_deps, const ResolvedDependencies& all_deps)
{
const fs::path cmake_util_dir = "cmake";
create_if_not_exist(cmake_util_dir);

static constexpr std::string_view kCmakeDepsDir = "${CMAKE_BINARY_DIR}/deps";

auto oss = fmt::output_file((cmake_util_dir / "deps.cmake").string());
oss.print("include(FetchContent)\n\n");

for (const auto& dep : deps) {
const auto& desc = get<GitHeaderOnlyDep>(dep.desc);
const auto& desc = get<GitDep>(dep.desc);

oss.print(R"(# Dep for {package}
FetchContent_Declare({package}
Expand All @@ -276,52 +280,49 @@ FetchContent_Declare({package}
SOURCE_DIR "{deps_dir}/{package}"
)
FetchContent_MakeAvailable({package})
message("-- Deps: download {package} from {git}:{commit}")
message("-- Deps: download {package} from {git}::{commit}")

)",
"package"_a = dep.package, "git"_a = desc.git, "commit"_a = desc.commit,
"deps_dir"_a = "${CMAKE_BINARY_DIR}/deps");
"package"_a = dep.package, "git"_a = desc.git, "commit"_a = desc.commit, "deps_dir"_a = kCmakeDepsDir);
}

// commit file
oss.print(R"(list(PREPEND CMAKE_PREFIX_PATH "${{CMAKE_SOURCE_DIR}}/cmake"))");
oss.print("\n");
oss.close();

for (const auto& dep : deps) {
write(cmake_util_dir / fmt::format("{}-config.cmake", dep.package),
fmt::format(R"(# export {package}
add_library(cppship::{package} INTERFACE IMPORTED)
target_include_directories(cppship::{package} INTERFACE ${{CMAKE_BINARY_DIR}}/deps/{package}/include)
)",
"package"_a = dep.package));
}
auto content_fix
= [deps_dir = deps_dir.string()](std::string& str) { boost::replace_all(str, deps_dir, kCmakeDepsDir); };
cmake::config_packages(cppship_deps, all_deps,
{
.deps_dir = deps_dir,
.out_dir = cmake_util_dir,
.cmake_deps_dir = std::string { kCmakeDepsDir },
.post_process = std::move(content_fix),
});

out << "include(cmake/deps.cmake)\n";
}

}

void CmakeDependencyInjector::inject(std::ostream& out, const Manifest& manifest)
void CmakeDependencyInjector::inject(std::ostream& out, const Manifest&)
{
const auto deps = concat(manifest.dependencies(), manifest.dev_dependencies());
if (deps.empty()) {
if (mDeclaredDeps.empty()) {
return;
}

const auto has_conan_deps
= any_of(deps, [](const DeclaredDependency& dep) { return std::holds_alternative<ConanDep>(dep.desc); });
const auto has_git_deps = any_of(
deps, [](const DeclaredDependency& dep) { return std::holds_alternative<GitHeaderOnlyDep>(dep.desc); });
const auto has_conan_deps = any_of(mDeclaredDeps, [](const DeclaredDependency& dep) { return dep.is_conan(); });

out << "\n# Dependency management\n";
if (has_conan_deps) {
inject_conan_deps(out);
}

if (has_git_deps) {
inject_git_deps(out, deps | filter([](const DeclaredDependency& dep) {
return std::holds_alternative<GitHeaderOnlyDep>(dep.desc);
}) | ranges::to<std::vector<DeclaredDependency>>());
if (!mCppshipDeps.empty()) {
const auto declared_cppship_deps = mDeclaredDeps
| filter([](const DeclaredDependency& dep) { return dep.is_git(); })
| ranges::to<std::vector<DeclaredDependency>>();
inject_git_deps(out, mDepsDir, declared_cppship_deps, mCppshipDeps, mAllDeps);
}
}
1 change: 1 addition & 0 deletions lib/cmake/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ void CmakeGenerator::add_lib_sources_()

cmake::CmakeLib lib({
.name = target->name,
.name_alias = target->name,
.include_dirs = target->includes,
.sources = target->sources,
.deps = mDeps,
Expand Down
6 changes: 5 additions & 1 deletion lib/cmake/lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ std::set<std::string> to_strings(const std::set<fs::path>& paths)

CmakeLib::CmakeLib(LibDesc desc)
: mName(std::move(desc.name))
, mNameAlias(std::move(desc.name_alias))
, mIncludes(to_strings(desc.include_dirs))
, mSources(to_strings(desc.sources))
, mDeps(desc.deps)
Expand All @@ -38,7 +39,10 @@ void CmakeLib::build(std::ostream& out) const
} else {
out << fmt::format("add_library({} {})\n", lib_name, boost::join(mSources, "\n"));
}
out << fmt::format(R"(set_target_properties({} PROPERTIES OUTPUT_NAME "{}"))", lib_name, mName) << '\n';

if (mNameAlias) {
out << fmt::format(R"(set_target_properties({} PROPERTIES OUTPUT_NAME "{}"))", lib_name, *mNameAlias) << '\n';
}

const std::string_view lib_type = is_interface() ? "INTERFACE" : "PUBLIC";
if (!mIncludes.empty()) {
Expand Down
58 changes: 58 additions & 0 deletions lib/cmake/package_configurer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "cppship/cmake/package_configurer.h"
#include "cppship/cmake/lib.h"
#include "cppship/core/layout.h"
#include "cppship/core/manifest.h"
#include "cppship/util/io.h"
#include "cppship/util/repo.h"

#include <fmt/core.h>
#include <fmt/format.h>

using namespace cppship;
using namespace fmt::literals;

void cmake::config_packages(
const ResolvedDependencies& cppship_deps, const ResolvedDependencies& all_deps, const ConfigOptions& options)
{
for (const auto& [package, dep] : cppship_deps) {
const auto& cmake_target = dep.cmake_target;
const auto package_dir = options.deps_dir / package;
const auto package_manifest = package_dir / kRepoConfigFile;
const auto package_cmake_config_file = options.out_dir / fmt::format("{}-config.cmake", package);

if (!fs::exists(package_manifest)) {
write(package_cmake_config_file,
fmt::format(R"(# header only lib config generated by cppship
add_library({target} INTERFACE IMPORTED)
target_include_directories({target} INTERFACE {cmake_deps_dir}/{package}/include)
)",
"target"_a = cmake_target, "package"_a = dep.package, "cmake_deps_dir"_a = options.cmake_deps_dir));

continue;
}

Manifest manifest(package_manifest);
Layout layout(package_dir, package);
const auto lib_target = *layout.lib();
const auto cmake_deps = cmake::collect_cmake_deps(manifest.dependencies(), all_deps);
cmake::CmakeLib lib({
.name = lib_target.name,
.include_dirs = lib_target.includes,
.sources = lib_target.sources,
.deps = cmake_deps,
.definitions = manifest.default_profile().definitions,
});

std::ostringstream out;
lib.build(out);

out << fmt::format("\nadd_library({} ALIAS {})\n", cmake_target, lib.target());

auto content = out.str();
if (const auto& func = options.post_process) {
func(content);
}

write(package_cmake_config_file, content);
}
}
38 changes: 2 additions & 36 deletions lib/cmd/build.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "cppship/cmd/build.h"
#include "cppship/cmake/generator.h"
#include "cppship/cmake/group.h"
#include "cppship/cmake/lib.h"
#include "cppship/cmake/package_configurer.h"
#include "cppship/core/compiler.h"
#include "cppship/core/dependency.h"
#include "cppship/core/resolver.h"
Expand Down Expand Up @@ -207,41 +207,7 @@ void cmd::conan_install(const BuildContext& ctx)
void cmd::cppship_install(
const BuildContext& ctx, const ResolvedDependencies& cppship_deps, const ResolvedDependencies& all_deps)
{
for (const auto& [package, dep] : cppship_deps) {
const auto cmake_target = fmt::format("cppship::{}", dep.package);
const auto package_dir = ctx.deps_dir / package;
const auto package_manifest = package_dir / kRepoConfigFile;
const auto package_cmake_config_file = ctx.deps_dir / fmt::format("{}-config.cmake", package);

if (!fs::exists(package_manifest)) {
write(package_cmake_config_file,
fmt::format(R"(# header only lib config generated by cppship
add_library({target} INTERFACE IMPORTED)
target_include_directories({target} INTERFACE ${{CMAKE_SOURCE_DIR}}/deps/{package}/include)
)",
"target"_a = cmake_target, "package"_a = dep.package));

continue;
}

Manifest manifest(package_manifest);
Layout layout(package_dir, package);
const auto lib_target = *layout.lib();
const auto cmake_deps = cmake::collect_cmake_deps(manifest.dependencies(), all_deps);
cmake::CmakeLib lib({
.name = lib_target.name,
.include_dirs = lib_target.includes,
.sources = lib_target.sources,
.deps = cmake_deps,
.definitions = manifest.default_profile().definitions,
});

std::ostringstream out;
lib.build(out);

out << fmt::format("\nadd_library({} ALIAS {})\n", cmake_target, lib.target());
write(package_cmake_config_file, out.str());
}
cmake::config_packages(cppship_deps, all_deps, { .deps_dir = ctx.deps_dir });
}

void cmd::cmake_setup(const BuildContext& ctx)
Expand Down
Loading