Separate template parsing and generation

* Reuse type for specifying template to use
* Add support for template add-function
* Add support for template pass-sources-to-add-function
main
cursey 3 years ago
parent 61d5e64d87
commit 2b7ee72e86
No known key found for this signature in database
GPG Key ID: A6A7163A1B8FD42C

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
// This is the type that will hold all the strings. // This is the type that will hold all the strings.
// Each enumeration type will declare its own specialization. // Each enumeration type will declare its own specialization.
@ -12,7 +13,7 @@
// be no definition of a generic version). // be no definition of a generic version).
template <typename T> template <typename T>
struct enumStrings { struct enumStrings {
static char const *data[]; static std::vector<std::string> data;
}; };
// This is a utility type. // This is a utility type.
@ -43,8 +44,8 @@ std::istream &operator>>(std::istream &str, enumRefHolder<T> const &data) {
// These two can be made easier to read in C++11 // These two can be made easier to read in C++11
// using std::begin() and std::end() // using std::begin() and std::end()
// //
static auto begin = std::begin(enumStrings<T>::data); auto begin = std::begin(enumStrings<T>::data);
static auto end = std::end(enumStrings<T>::data); auto end = std::end(enumStrings<T>::data);
auto find = std::find(begin, end, value); auto find = std::find(begin, end, value);
if (find != end) { if (find != end) {

@ -56,11 +56,14 @@ enum TargetType {
target_interface, target_interface,
target_custom, target_custom,
target_object, target_object,
target_template,
target_COUNT,
}; };
struct Target { struct Target {
std::string name; std::string name;
TargetType type = {}; TargetType type = {};
std::string type_string;
ConditionVector headers; ConditionVector headers;
ConditionVector sources; ConditionVector sources;
@ -100,6 +103,12 @@ struct Target {
ConditionVector include_after; ConditionVector include_after;
}; };
struct Template {
Target outline;
std::string add_function;
bool pass_sources_to_add_function = false;
};
struct Test { struct Test {
std::string name; std::string name;
std::string condition; std::string condition;
@ -160,12 +169,12 @@ struct Project {
std::vector<Package> packages; std::vector<Package> packages;
Vcpkg vcpkg; Vcpkg vcpkg;
std::vector<Content> contents; std::vector<Content> contents;
std::vector<Template> templates;
std::vector<Target> targets; std::vector<Target> targets;
std::vector<Test> tests; std::vector<Test> tests;
std::vector<Install> installs; std::vector<Install> installs;
tsl::ordered_map<std::string, std::string> conditions; tsl::ordered_map<std::string, std::string> conditions;
std::vector<Subdir> subdirs; std::vector<Subdir> subdirs;
std::vector<Target> templates;
Project(const Project *parent, const std::string &path, bool build); Project(const Project *parent, const std::string &path, bool build);
}; };

@ -8,6 +8,7 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <memory>
namespace cmkr { namespace cmkr {
namespace gen { namespace gen {
@ -771,12 +772,31 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
} }
const auto &target = project.targets[i]; const auto &target = project.targets[i];
const parser::Template *tmplate = nullptr;
std::unique_ptr<ConditionScope> tmplate_cs{};
comment("Target " + target.name); comment("Target " + target.name);
// Check if this target is using a template.
if (target.type == parser::target_template) {
for (const auto &t : project.templates) {
if (target.type_string == t.outline.name) {
tmplate = &t;
tmplate_cs = std::make_unique<ConditionScope>(gen, tmplate->outline.condition);
}
}
}
ConditionScope cs(gen, target.condition); ConditionScope cs(gen, target.condition);
cmd("set")("CMKR_TARGET", target.name); cmd("set")("CMKR_TARGET", target.name);
if (tmplate != nullptr) {
gen.handle_condition(tmplate->outline.include_before,
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
gen.handle_condition(tmplate->outline.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
}
gen.handle_condition(target.include_before, gen.handle_condition(target.include_before,
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); }); [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
gen.handle_condition(target.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); gen.handle_condition(target.cmake_before, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
@ -785,6 +805,18 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
bool added_toml = false; bool added_toml = false;
cmd("set")(sources_var, RawArg("\"\"")).endl(); cmd("set")(sources_var, RawArg("\"\"")).endl();
if (tmplate != nullptr) {
gen.handle_condition(tmplate->outline.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) {
auto sources = expand_cmake_paths(condition_sources, path);
if (sources.empty()) {
auto source_key = condition.empty() ? "sources" : (condition + ".sources");
throw std::runtime_error(target.name + " " + source_key + " wildcard found 0 files");
}
cmd("list")("APPEND", sources_var, sources);
});
}
gen.handle_condition(target.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) { gen.handle_condition(target.sources, [&](const std::string &condition, const std::vector<std::string> &condition_sources) {
auto sources = expand_cmake_paths(condition_sources, path); auto sources = expand_cmake_paths(condition_sources, path);
if (sources.empty()) { if (sources.empty()) {
@ -798,66 +830,89 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
cmd("list")("APPEND", sources_var, sources); cmd("list")("APPEND", sources_var, sources);
}); });
if (!added_toml && target.type != parser::target_interface) { auto target_type = target.type;
if (tmplate != nullptr) {
target_type = tmplate->outline.type;
}
if (!added_toml && target_type != parser::target_interface) {
cmd("list")("APPEND", sources_var, std::vector<std::string>{"cmake.toml"}).endl(); cmd("list")("APPEND", sources_var, std::vector<std::string>{"cmake.toml"}).endl();
} }
cmd("set")("CMKR_SOURCES", "${" + sources_var + "}"); cmd("set")("CMKR_SOURCES", "${" + sources_var + "}");
std::string add_command; std::string add_command;
std::string target_type; std::string target_type_string;
std::string target_scope; std::string target_scope;
switch (target.type) {
switch (target_type) {
case parser::target_executable: case parser::target_executable:
add_command = "add_executable"; add_command = "add_executable";
target_type = ""; target_type_string = "";
target_scope = "PRIVATE"; target_scope = "PRIVATE";
break; break;
case parser::target_library: case parser::target_library:
add_command = "add_library"; add_command = "add_library";
target_type = ""; target_type_string = "";
target_scope = "PUBLIC"; target_scope = "PUBLIC";
break; break;
case parser::target_shared: case parser::target_shared:
add_command = "add_library"; add_command = "add_library";
target_type = "SHARED"; target_type_string = "SHARED";
target_scope = "PUBLIC"; target_scope = "PUBLIC";
break; break;
case parser::target_static: case parser::target_static:
add_command = "add_library"; add_command = "add_library";
target_type = "STATIC"; target_type_string = "STATIC";
target_scope = "PUBLIC"; target_scope = "PUBLIC";
break; break;
case parser::target_interface: case parser::target_interface:
add_command = "add_library"; add_command = "add_library";
target_type = "INTERFACE"; target_type_string = "INTERFACE";
target_scope = "INTERFACE"; target_scope = "INTERFACE";
break; break;
case parser::target_custom: case parser::target_custom:
// TODO: add proper support, this is hacky // TODO: add proper support, this is hacky
add_command = "add_custom_target"; add_command = "add_custom_target";
target_type = "SOURCES"; target_type_string = "SOURCES";
target_scope = "PUBLIC"; target_scope = "PUBLIC";
break; break;
case parser::target_object: case parser::target_object:
// NOTE: This is properly supported since 3.12 // NOTE: This is properly supported since 3.12
add_command = "add_library"; add_command = "add_library";
target_type = "OBJECT"; target_type_string = "OBJECT";
target_scope = "PUBLIC"; target_scope = "PUBLIC";
break; break;
default: default:
throw std::runtime_error("Unimplemented enum value"); throw std::runtime_error("Unimplemented enum value");
} }
cmd(add_command)(target.name, target_type).endl(); // Handle custom add commands from templates.
if (tmplate != nullptr && !tmplate->add_function.empty()) {
add_command = tmplate->add_function;
target_type_string = ""; // TODO: let templates supply options to the add_command here?
if (tmplate->pass_sources_to_add_function) {
cmd(add_command)(target.name, target_type_string, "${" + sources_var + "}");
} else {
// clang-format off
cmd("if")(sources_var);
cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}");
cmd("endif")().endl();
// clang-format on
}
} else {
cmd(add_command)(target.name, target_type_string).endl();
// clang-format off // clang-format off
cmd("if")(sources_var); cmd("if")(sources_var);
cmd("target_sources")(target.name, target.type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}"); cmd("target_sources")(target.name, target_type == parser::target_interface ? "INTERFACE" : "PRIVATE", "${" + sources_var + "}");
cmd("endif")().endl(); cmd("endif")().endl();
// clang-format on // clang-format on
}
// The first executable target will become the Visual Studio startup project // The first executable target will become the Visual Studio startup project
if (target.type == parser::target_executable) { if (target_type == parser::target_executable) {
cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT"); cmd("get_directory_property")("CMKR_VS_STARTUP_PROJECT", "DIRECTORY", "${PROJECT_SOURCE_DIR}", "DEFINITION", "VS_STARTUP_PROJECT");
// clang-format off // clang-format off
cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT"); cmd("if")("NOT", "CMKR_VS_STARTUP_PROJECT");
@ -879,6 +934,34 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
[&](const std::string &, const std::vector<std::string> &args) { cmd(command)(target.name, scope, args); }); [&](const std::string &, const std::vector<std::string> &args) { cmd(command)(target.name, scope, args); });
}; };
if (tmplate != nullptr) {
const auto &outline = tmplate->outline;
target_cmd("target_compile_definitions", outline.compile_definitions, target_scope);
target_cmd("target_compile_definitions", outline.private_compile_definitions, "PRIVATE");
target_cmd("target_compile_features", outline.compile_features, target_scope);
target_cmd("target_compile_features", outline.private_compile_features, "PRIVATE");
target_cmd("target_compile_options", outline.compile_options, target_scope);
target_cmd("target_compile_options", outline.private_compile_options, "PRIVATE");
target_cmd("target_include_directories", outline.include_directories, target_scope);
target_cmd("target_include_directories", outline.private_include_directories, "PRIVATE");
target_cmd("target_link_directories", outline.link_directories, target_scope);
target_cmd("target_link_directories", outline.private_link_directories, "PRIVATE");
target_cmd("target_link_libraries", outline.link_libraries, target_scope);
target_cmd("target_link_libraries", outline.private_link_libraries, "PRIVATE");
target_cmd("target_link_options", outline.link_options, target_scope);
target_cmd("target_link_options", outline.private_link_options, "PRIVATE");
target_cmd("target_precompile_headers", outline.precompile_headers, target_scope);
target_cmd("target_precompile_headers", outline.private_precompile_headers, "PRIVATE");
}
target_cmd("target_compile_definitions", target.compile_definitions, target_scope); target_cmd("target_compile_definitions", target.compile_definitions, target_scope);
target_cmd("target_compile_definitions", target.private_compile_definitions, "PRIVATE"); target_cmd("target_compile_definitions", target.private_compile_definitions, "PRIVATE");
@ -903,8 +986,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
target_cmd("target_precompile_headers", target.precompile_headers, target_scope); target_cmd("target_precompile_headers", target.precompile_headers, target_scope);
target_cmd("target_precompile_headers", target.private_precompile_headers, "PRIVATE"); target_cmd("target_precompile_headers", target.private_precompile_headers, "PRIVATE");
if (!target.properties.empty()) { if (!target.properties.empty() || (tmplate != nullptr && !tmplate->outline.properties.empty())) {
gen.handle_condition(target.properties, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) { auto props = target.properties;
if (tmplate != nullptr) {
props.insert(tmplate->outline.properties.begin(), tmplate->outline.properties.end());
}
gen.handle_condition(props, [&](const std::string &, const tsl::ordered_map<std::string, std::string> &properties) {
cmd("set_target_properties")(target.name, "PROPERTIES", properties); cmd("set_target_properties")(target.name, "PROPERTIES", properties);
}); });
} }
@ -913,6 +1002,12 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); }); [&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
gen.handle_condition(target.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); }); gen.handle_condition(target.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
if (tmplate != nullptr) {
gen.handle_condition(tmplate->outline.include_after,
[&](const std::string &, const std::vector<std::string> &includes) { inject_includes(includes); });
gen.handle_condition(tmplate->outline.cmake_after, [&](const std::string &, const std::string &cmake) { inject_cmake(cmake); });
}
cmd("unset")("CMKR_TARGET"); cmd("unset")("CMKR_TARGET");
cmd("unset")("CMKR_SOURCES"); cmd("unset")("CMKR_SOURCES");
} }

@ -8,7 +8,8 @@
#include <tsl/ordered_map.h> #include <tsl/ordered_map.h>
template <> template <>
const char *enumStrings<cmkr::parser::TargetType>::data[] = {"executable", "library", "shared", "static", "interface", "custom", "object"}; std::vector<std::string> enumStrings<cmkr::parser::TargetType>::data{"executable", "library", "shared", "static",
"interface", "custom", "object", "template"};
namespace cmkr { namespace cmkr {
namespace parser { namespace parser {
@ -96,36 +97,6 @@ class TomlChecker {
visit(ky); visit(ky);
} }
template <typename T>
void optional_append(const toml::key &ky, Condition<T> &destination) {
// TODO: this algorithm in O(n) over the amount of keys, kinda bad
const auto &table = m_v.as_table();
for (const auto &itr : table) {
const auto &key = itr.first;
const auto &value = itr.second;
T *dest = nullptr;
if (value.is_table()) {
if (value.contains(ky)) {
dest = &destination[key];
}
} else if (key == ky) {
dest = &destination[""];
}
if (dest != nullptr) {
const auto &items = toml::find<T>(m_v, ky);
dest->insert(dest->end(), items.begin(), items.end());
}
}
// Handle visiting logic
for (const auto &itr : destination) {
if (!itr.first.empty()) {
m_conditionVisited.emplace(itr.first, true);
}
}
visit(ky);
}
template <typename T> template <typename T>
void optional(const toml::key &ky, T &destination) { void optional(const toml::key &ky, T &destination) {
// TODO: this currently doesn't allow you to get an optional map<string, X> // TODO: this currently doesn't allow you to get an optional map<string, X>
@ -135,17 +106,6 @@ class TomlChecker {
visit(ky); visit(ky);
} }
template <typename T>
void optional_append(const toml::key &ky, T &destination) {
// TODO: this currently doesn't allow you to get an optional map<string, X>
if (m_v.contains(ky)) {
const auto &items = toml::find<T>(m_v, ky);
destination.insert(destination.end(), items.begin(), items.end());
}
visit(ky);
}
template <typename T> template <typename T>
void required(const toml::key &ky, T &destination) { void required(const toml::key &ky, T &destination) {
destination = toml::find<T>(m_v, ky); destination = toml::find<T>(m_v, ky);
@ -427,129 +387,116 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
throw std::runtime_error("[[bin]] has been renamed to [[target]]"); throw std::runtime_error("[[bin]] has been renamed to [[target]]");
} }
if (toml.contains("target") || toml.contains("template")) { auto parse_target = [&](const std::string &name, TomlChecker& t) {
const toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector> empty_templates_table = toml::table(); Target target;
auto tables = { target.name = name;
toml.contains("template") ? &toml::find(toml, "template") : &empty_templates_table,
&toml::find(toml, "target")
};
auto is_template = true;
for (const auto &ts : tables) {
for (const auto &itr : ts->as_table()) {
const auto &value = itr.second;
auto &t = checker.create(value);
std::string template_name;
if (!is_template) {
t.optional("template", template_name);
}
Target target; t.required("type", target.type_string);
auto from_template = false;
if (!template_name.empty()) {
for (const auto & template_ : templates) {
if (template_name == template_.name) {
from_template = true;
target = template_;
}
}
if (!from_template) { target.type = to_enum<TargetType>(target.type_string, "target type");
throw std::runtime_error("Could not find template named " + template_name);
}
}
target.name = itr.first; if (target.type >= target_COUNT) {
target.type = target_template;
}
if (!from_template) { t.optional("headers", target.headers);
std::string type; t.optional("sources", target.sources);
t.required("type", type);
target.type = to_enum<TargetType>(type, "target type");
}
t.optional_append("headers", target.headers); t.optional("compile-definitions", target.compile_definitions);
t.optional_append("sources", target.sources); t.optional("private-compile-definitions", target.private_compile_definitions);
t.optional_append("compile-definitions", target.compile_definitions); t.optional("compile-features", target.compile_features);
t.optional_append("private-compile-definitions", target.private_compile_definitions); t.optional("private-compile-features", target.private_compile_features);
t.optional_append("compile-features", target.compile_features); t.optional("compile-options", target.compile_options);
t.optional_append("private-compile-features", target.private_compile_features); t.optional("private-compile-options", target.private_compile_options);
t.optional_append("compile-options", target.compile_options); t.optional("include-directories", target.include_directories);
t.optional_append("private-compile-options", target.private_compile_options); t.optional("private-include-directories", target.private_include_directories);
t.optional_append("include-directories", target.include_directories); t.optional("link-directories", target.link_directories);
t.optional_append("private-include-directories", target.private_include_directories); t.optional("private-link-directories", target.private_link_directories);
t.optional_append("link-directories", target.link_directories); t.optional("link-libraries", target.link_libraries);
t.optional_append("private-link-directories", target.private_link_directories); t.optional("private-link-libraries", target.private_link_libraries);
t.optional_append("link-libraries", target.link_libraries); t.optional("link-options", target.link_options);
t.optional_append("private-link-libraries", target.private_link_libraries); t.optional("private-link-options", target.private_link_options);
t.optional_append("link-options", target.link_options); t.optional("precompile-headers", target.precompile_headers);
t.optional_append("private-link-options", target.private_link_options); t.optional("private-precompile-headers", target.private_precompile_headers);
t.optional_append("precompile-headers", target.precompile_headers); if (!target.headers.empty()) {
t.optional_append("private-precompile-headers", target.private_precompile_headers); auto &sources = target.sources.nth(0).value();
const auto &headers = target.headers.nth(0)->second;
sources.insert(sources.end(), headers.begin(), headers.end());
}
if (!target.headers.empty()) { t.optional("condition", target.condition);
auto &sources = target.sources.nth(0).value(); t.optional("alias", target.alias);
const auto &headers = target.headers.nth(0)->second;
sources.insert(sources.end(), headers.begin(), headers.end());
}
t.optional("condition", target.condition); if (t.contains("properties")) {
t.optional("alias", target.alias); auto store_property = [&target](const toml::key &k, const TomlBasicValue &v, const std::string &condition) {
if (v.is_array()) {
if (t.contains("properties")) { std::string property_list;
auto store_property = [&target](const toml::key &k, const TomlBasicValue &v, const std::string &condition) { for (const auto &list_val : v.as_array()) {
if (v.is_array()) { if (!property_list.empty()) {
std::string property_list; property_list += ';';
for (const auto &list_val : v.as_array()) {
if (!property_list.empty()) {
property_list += ';';
}
property_list += list_val.as_string();
}
target.properties[condition][k] = property_list;
} else if (v.is_boolean()) {
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
} else {
target.properties[condition][k] = v.as_string();
}
};
const auto &props = t.find("properties").as_table();
for (const auto &propKv : props) {
const auto &k = propKv.first;
const auto &v = propKv.second;
if (v.is_table()) {
for (const auto &condKv : v.as_table()) {
store_property(condKv.first, condKv.second, k);
}
} else {
store_property(k, v, "");
} }
property_list += list_val.as_string();
} }
target.properties[condition][k] = property_list;
} else if (v.is_boolean()) {
target.properties[condition][k] = v.as_boolean() ? "ON" : "OFF";
} else {
target.properties[condition][k] = v.as_string();
} }
};
t.optional("cmake-before", target.cmake_before);
t.optional("cmake-after", target.cmake_after); const auto &props = t.find("properties").as_table();
t.optional_append("include-before", target.include_before); for (const auto &propKv : props) {
t.optional_append("include-after", target.include_after); const auto &k = propKv.first;
const auto &v = propKv.second;
if (is_template) { if (v.is_table()) {
templates.push_back(target); for (const auto &condKv : v.as_table()) {
store_property(condKv.first, condKv.second, k);
}
} else { } else {
targets.push_back(target); store_property(k, v, "");
} }
} }
}
t.optional("cmake-before", target.cmake_before);
t.optional("cmake-after", target.cmake_after);
t.optional("include-before", target.include_before);
t.optional("include-after", target.include_after);
return target;
};
if (toml.contains("template")) {
const auto &ts = toml::find(toml, "template").as_table();
for (const auto &itr : ts) {
Template tmplate;
auto& t = checker.create(itr.second);
tmplate.outline = parse_target(itr.first, t);
t.optional("add-function", tmplate.add_function);
t.optional("pass-sources-to-add-function", tmplate.pass_sources_to_add_function);
templates.push_back(tmplate);
enumStrings<TargetType>::data.push_back(tmplate.outline.name);
}
}
if (toml.contains("target")) {
const auto &ts = toml::find(toml, "target").as_table();
is_template = false; for (const auto &itr : ts) {
auto& t = checker.create(itr.second);
targets.push_back(parse_target(itr.first, t));
} }
} }

@ -0,0 +1,19 @@
# A project using templates to build a driver.
[project]
name = "driver"
description = "Driver example"
cmake-after = "list(APPEND CMAKE_MODULE_PATH cmake)"
[find-package]
WDK = { required = true }
[template.driver]
type = "shared"
add-function = "wdk_add_driver"
pass-sources-to-add-function = true
[target.cool-driver]
type = "driver"
sources = ["src/DriverEntry.cpp"]

@ -0,0 +1,179 @@
# Redistribution and use is allowed under the OSI-approved 3-clause BSD license.
# Copyright (c) 2018 Sergey Podobry (sergey.podobry at gmail.com). All rights reserved.
#.rst:
# FindWDK
# ----------
#
# This module searches for the installed Windows Development Kit (WDK) and
# exposes commands for creating kernel drivers and kernel libraries.
#
# Output variables:
# - `WDK_FOUND` -- if false, do not try to use WDK
# - `WDK_ROOT` -- where WDK is installed
# - `WDK_VERSION` -- the version of the selected WDK
# - `WDK_WINVER` -- the WINVER used for kernel drivers and libraries
# (default value is `0x0601` and can be changed per target or globally)
#
# Example usage:
#
# find_package(WDK REQUIRED)
#
# wdk_add_library(KmdfCppLib STATIC KMDF 1.15
# KmdfCppLib.h
# KmdfCppLib.cpp
# )
# target_include_directories(KmdfCppLib INTERFACE .)
#
# wdk_add_driver(KmdfCppDriver KMDF 1.15
# Main.cpp
# )
# target_link_libraries(KmdfCppDriver KmdfCppLib)
#
if(DEFINED ENV{WDKContentRoot})
file(GLOB WDK_NTDDK_FILES
"$ENV{WDKContentRoot}/Include/*/km/ntddk.h"
)
else()
file(GLOB WDK_NTDDK_FILES
"C:/Program Files*/Windows Kits/10/Include/*/km/ntddk.h"
)
endif()
if(WDK_NTDDK_FILES)
list(GET WDK_NTDDK_FILES -1 WDK_LATEST_NTDDK_FILE)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WDK REQUIRED_VARS WDK_LATEST_NTDDK_FILE)
if (NOT WDK_LATEST_NTDDK_FILE)
return()
endif()
get_filename_component(WDK_ROOT ${WDK_LATEST_NTDDK_FILE} DIRECTORY)
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY)
get_filename_component(WDK_VERSION ${WDK_ROOT} NAME)
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY)
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY)
message(STATUS "WDK_ROOT: " ${WDK_ROOT})
message(STATUS "WDK_VERSION: " ${WDK_VERSION})
set(WDK_WINVER "0x0601" CACHE STRING "Default WINVER for WDK targets")
set(WDK_ADDITIONAL_FLAGS_FILE "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/wdkflags.h")
file(WRITE ${WDK_ADDITIONAL_FLAGS_FILE} "#pragma runtime_checks(\"suc\", off)")
set(WDK_COMPILE_FLAGS
"/Zp8" # set struct alignment
"/GF" # enable string pooling
"/GR-" # disable RTTI
"/Gz" # __stdcall by default
"/kernel" # create kernel mode binary
"/FIwarning.h" # disable warnings in WDK headers
"/FI${WDK_ADDITIONAL_FLAGS_FILE}" # include file to disable RTC
)
set(WDK_COMPILE_DEFINITIONS "WINNT=1")
set(WDK_COMPILE_DEFINITIONS_DEBUG "MSC_NOOPT;DEPRECATE_DDK_FUNCTIONS=1;DBG=1")
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
list(APPEND WDK_COMPILE_DEFINITIONS "_X86_=1;i386=1;STD_CALL")
set(WDK_PLATFORM "x86")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND WDK_COMPILE_DEFINITIONS "_WIN64;_AMD64_;AMD64")
set(WDK_PLATFORM "x64")
else()
message(FATAL_ERROR "Unsupported architecture")
endif()
string(CONCAT WDK_LINK_FLAGS
"/MANIFEST:NO " #
"/DRIVER " #
"/OPT:REF " #
"/INCREMENTAL:NO " #
"/OPT:ICF " #
"/SUBSYSTEM:NATIVE " #
"/MERGE:_TEXT=.text;_PAGE=PAGE " #
"/NODEFAULTLIB " # do not link default CRT
"/SECTION:INIT,d " #
"/VERSION:10.0 " #
)
# Generate imported targets for WDK lib files
file(GLOB WDK_LIBRARIES "${WDK_ROOT}/Lib/${WDK_VERSION}/km/${WDK_PLATFORM}/*.lib")
foreach(LIBRARY IN LISTS WDK_LIBRARIES)
get_filename_component(LIBRARY_NAME ${LIBRARY} NAME_WE)
string(TOUPPER ${LIBRARY_NAME} LIBRARY_NAME)
add_library(WDK::${LIBRARY_NAME} INTERFACE IMPORTED)
set_property(TARGET WDK::${LIBRARY_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBRARY})
endforeach(LIBRARY)
unset(WDK_LIBRARIES)
function(wdk_add_driver _target)
cmake_parse_arguments(WDK "" "KMDF;WINVER" "" ${ARGN})
add_executable(${_target} ${WDK_UNPARSED_ARGUMENTS})
set_target_properties(${_target} PROPERTIES SUFFIX ".sys")
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}")
set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS
"${WDK_COMPILE_DEFINITIONS};$<$<CONFIG:Debug>:${WDK_COMPILE_DEFINITIONS_DEBUG}>;_WIN32_WINNT=${WDK_WINVER}"
)
set_target_properties(${_target} PROPERTIES LINK_FLAGS "${WDK_LINK_FLAGS}")
target_include_directories(${_target} SYSTEM PRIVATE
"${WDK_ROOT}/Include/${WDK_VERSION}/shared"
"${WDK_ROOT}/Include/${WDK_VERSION}/km"
"${WDK_ROOT}/Include/${WDK_VERSION}/km/crt"
)
target_link_libraries(${_target} WDK::NTOSKRNL WDK::HAL WDK::BUFFEROVERFLOWK WDK::WMILIB)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
target_link_libraries(${_target} WDK::MEMCMP)
endif()
if(DEFINED WDK_KMDF)
target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}")
target_link_libraries(${_target}
"${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfDriverEntry.lib"
"${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfLdr.lib"
)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry@8")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry")
endif()
else()
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry@8")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry")
endif()
endif()
endfunction()
function(wdk_add_library _target)
cmake_parse_arguments(WDK "" "KMDF;WINVER" "" ${ARGN})
add_library(${_target} ${WDK_UNPARSED_ARGUMENTS})
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}")
set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS
"${WDK_COMPILE_DEFINITIONS};$<$<CONFIG:Debug>:${WDK_COMPILE_DEFINITIONS_DEBUG};>_WIN32_WINNT=${WDK_WINVER}"
)
target_include_directories(${_target} SYSTEM PRIVATE
"${WDK_ROOT}/Include/${WDK_VERSION}/shared"
"${WDK_ROOT}/Include/${WDK_VERSION}/km"
"${WDK_ROOT}/Include/${WDK_VERSION}/km/crt"
)
if(DEFINED WDK_KMDF)
target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}")
endif()
endfunction()

@ -0,0 +1,5 @@
#include <ntifs.h>
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING registry) {
return STATUS_UNSUCCESSFUL;
}

@ -10,9 +10,9 @@ sources = ["src/templates.cpp"]
compile-definitions = ["IS_APP=true"] compile-definitions = ["IS_APP=true"]
[target.app-a] [target.app-a]
template = "app" type = "app"
compile-definitions = ["APP_A"] compile-definitions = ["APP_A"]
[target.app-b] [target.app-b]
template = "app" type = "app"
compile-definitions = ["APP_B"] compile-definitions = ["APP_B"]

Loading…
Cancel
Save