2019-10-17 23:44:10 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Emit CMake file list
|
|
|
|
//
|
2019-11-08 03:33:59 +00:00
|
|
|
// Code available from: https://verilator.org
|
2019-10-17 23:44:10 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2023-01-01 15:18:39 +00:00
|
|
|
// Copyright 2004-2023 by Wilson Snyder. This program is free software; you
|
2020-03-21 15:24:24 +00:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2019-10-17 23:44:10 +00:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
// Version 2.0.
|
2020-03-21 15:24:24 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2019-10-17 23:44:10 +00:00
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
#include "V3EmitCMake.h"
|
2022-08-05 09:56:57 +00:00
|
|
|
|
2019-10-17 23:44:10 +00:00
|
|
|
#include "V3EmitCBase.h"
|
2022-08-05 09:56:57 +00:00
|
|
|
#include "V3Global.h"
|
2020-08-15 13:43:53 +00:00
|
|
|
#include "V3HierBlock.h"
|
2022-08-05 09:56:57 +00:00
|
|
|
#include "V3Os.h"
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
2022-09-18 19:53:42 +00:00
|
|
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
|
|
|
|
|
|
|
// ######################################################################
|
|
|
|
// Emit statements
|
2019-10-17 23:44:10 +00:00
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class CMakeEmitter final {
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
|
|
|
// STATIC FUNCTIONS
|
|
|
|
|
|
|
|
// Concatenate all strings in 'strs' with ' ' between them.
|
2022-08-05 09:56:57 +00:00
|
|
|
template <typename List>
|
|
|
|
static string cmake_list(const List& strs) {
|
2019-10-17 23:44:10 +00:00
|
|
|
string s;
|
|
|
|
if (strs.begin() != strs.end()) {
|
|
|
|
s.append("\"");
|
2020-08-15 13:43:53 +00:00
|
|
|
s.append(VString::quoteAny(*strs.begin(), '"', '\\'));
|
2019-10-17 23:44:10 +00:00
|
|
|
s.append("\"");
|
|
|
|
for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) {
|
|
|
|
s.append(" \"");
|
2020-08-15 13:43:53 +00:00
|
|
|
s.append(VString::quoteAny(*it, '"', '\\'));
|
2019-10-17 23:44:10 +00:00
|
|
|
s.append("\"");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print CMake variable set command: output raw_value unmodified
|
|
|
|
// cache_type should be empty for a normal variable
|
|
|
|
// "BOOL", "FILEPATH", "PATH", "STRING" or "INTERNAL" for a CACHE variable
|
|
|
|
// See https://cmake.org/cmake/help/latest/command/set.html
|
|
|
|
static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value,
|
2020-04-15 11:58:34 +00:00
|
|
|
const string& cache_type = "", const string& docstring = "") {
|
2019-10-17 23:44:10 +00:00
|
|
|
of << "set(" << name << " " << raw_value;
|
2021-02-22 02:25:21 +00:00
|
|
|
if (!cache_type.empty()) of << " CACHE " << cache_type << " \"" << docstring << "\"";
|
2019-10-17 23:44:10 +00:00
|
|
|
of << ")\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cmake_set(std::ofstream& of, const string& name, const string& value,
|
2020-04-15 11:58:34 +00:00
|
|
|
const string& cache_type = "", const string& docstring = "") {
|
2021-06-20 22:32:57 +00:00
|
|
|
const string raw_value = "\"" + value + "\"";
|
2019-10-17 23:44:10 +00:00
|
|
|
cmake_set_raw(of, name, raw_value, cache_type, docstring);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void emitOverallCMake() {
|
2021-07-11 22:42:01 +00:00
|
|
|
const std::unique_ptr<std::ofstream> of{
|
|
|
|
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake")};
|
2021-06-20 22:32:57 +00:00
|
|
|
const string name = v3Global.opt.prefix();
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
*of << "# Verilated -*- CMake -*-\n";
|
2020-04-15 11:58:34 +00:00
|
|
|
*of << "# DESCR"
|
|
|
|
"IPTION: Verilator output: CMake include script with class lists\n";
|
2019-10-17 23:44:10 +00:00
|
|
|
*of << "#\n";
|
2020-04-15 11:58:34 +00:00
|
|
|
*of << "# This CMake script lists generated Verilated files, for "
|
|
|
|
"including in higher level CMake scripts.\n";
|
2019-10-17 23:44:10 +00:00
|
|
|
*of << "# This file is meant to be consumed by the verilate() function,\n";
|
|
|
|
*of << "# which becomes available after executing `find_package(verilator).\n";
|
|
|
|
|
|
|
|
*of << "\n### Constants...\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set(*of, "PERL", V3Options::getenvPERL(), "FILEPATH",
|
2020-04-15 11:58:34 +00:00
|
|
|
"Perl executable (from $PERL)");
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set(*of, "VERILATOR_ROOT", V3Options::getenvVERILATOR_ROOT(), "PATH",
|
2020-04-15 11:58:34 +00:00
|
|
|
"Path to Verilator kit (from $VERILATOR_ROOT)");
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
*of << "\n### Compiler flags...\n";
|
|
|
|
|
|
|
|
*of << "# User CFLAGS (from -CFLAGS on Verilator command line)\n";
|
|
|
|
cmake_set_raw(*of, name + "_USER_CFLAGS", cmake_list(v3Global.opt.cFlags()));
|
|
|
|
|
|
|
|
*of << "# User LDLIBS (from -LDFLAGS on Verilator command line)\n";
|
|
|
|
cmake_set_raw(*of, name + "_USER_LDLIBS", cmake_list(v3Global.opt.ldLibs()));
|
|
|
|
|
|
|
|
*of << "\n### Switches...\n";
|
|
|
|
|
|
|
|
*of << "# SystemC output mode? 0/1 (from --sc)\n";
|
|
|
|
cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0");
|
|
|
|
*of << "# Coverage output mode? 0/1 (from --coverage)\n";
|
2020-04-15 11:58:34 +00:00
|
|
|
cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0");
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
*of << "# Timing mode? 0/1\n";
|
|
|
|
cmake_set_raw(*of, name + "_TIMING", v3Global.usesTiming() ? "1" : "0");
|
2022-11-05 12:47:34 +00:00
|
|
|
*of << "# Threaded output mode? 1/N threads (from --threads)\n";
|
2019-10-17 23:44:10 +00:00
|
|
|
cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads()));
|
|
|
|
*of << "# VCD Tracing output mode? 0/1 (from --trace)\n";
|
2020-04-15 11:58:34 +00:00
|
|
|
cmake_set_raw(*of, name + "_TRACE_VCD",
|
2022-05-20 15:02:43 +00:00
|
|
|
(v3Global.opt.trace() && v3Global.opt.traceFormat().vcd()) ? "1" : "0");
|
|
|
|
*of << "# FST Tracing output mode? 0/1 (from --trace-fst)\n";
|
2020-04-15 11:58:34 +00:00
|
|
|
cmake_set_raw(*of, name + "_TRACE_FST",
|
2022-05-20 15:02:43 +00:00
|
|
|
(v3Global.opt.trace() && v3Global.opt.traceFormat().fst()) ? "1" : "0");
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
*of << "\n### Sources...\n";
|
2020-08-16 18:55:46 +00:00
|
|
|
std::vector<string> classes_fast;
|
|
|
|
std::vector<string> classes_slow;
|
|
|
|
std::vector<string> support_fast;
|
|
|
|
std::vector<string> support_slow;
|
|
|
|
std::vector<string> global;
|
2020-01-22 00:54:14 +00:00
|
|
|
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
2021-10-22 12:56:48 +00:00
|
|
|
nodep = VN_AS(nodep->nextp(), NodeFile)) {
|
2021-11-13 18:50:44 +00:00
|
|
|
const AstCFile* const cfilep = VN_CAST(nodep, CFile);
|
2019-10-17 23:44:10 +00:00
|
|
|
if (cfilep && cfilep->source()) {
|
|
|
|
if (cfilep->support()) {
|
|
|
|
if (cfilep->slow()) {
|
|
|
|
support_slow.push_back(cfilep->name());
|
|
|
|
} else {
|
|
|
|
support_fast.push_back(cfilep->name());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cfilep->slow()) {
|
|
|
|
classes_slow.push_back(cfilep->name());
|
|
|
|
} else {
|
|
|
|
classes_fast.push_back(cfilep->name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated.cpp");
|
2020-04-15 11:58:34 +00:00
|
|
|
if (v3Global.dpi()) { //
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
|
|
|
if (v3Global.opt.vpi()) {
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
|
|
|
if (v3Global.opt.savable()) {
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_save.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
|
|
|
if (v3Global.opt.coverage()) {
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
|
|
|
if (v3Global.opt.trace()) {
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
|
|
|
|
+ "_c.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
2022-12-04 22:30:51 +00:00
|
|
|
if (v3Global.usesProbDist()) {
|
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_probdist.cpp");
|
|
|
|
}
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
if (v3Global.usesTiming()) {
|
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_timing.cpp");
|
|
|
|
}
|
2022-07-12 10:41:15 +00:00
|
|
|
if (v3Global.opt.threads()) {
|
2020-11-11 02:40:14 +00:00
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
2022-03-25 19:46:50 +00:00
|
|
|
if (v3Global.opt.usesProfiler()) {
|
|
|
|
global.emplace_back("${VERILATOR_ROOT}/include/verilated_profiler.cpp");
|
|
|
|
}
|
2021-11-14 14:39:31 +00:00
|
|
|
if (!v3Global.opt.libCreate().empty()) {
|
|
|
|
global.emplace_back(v3Global.opt.makeDir() + "/" + v3Global.opt.libCreate() + ".cpp");
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*of << "# Global classes, need linked once per executable\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_GLOBAL", cmake_list(global));
|
2019-10-17 23:44:10 +00:00
|
|
|
*of << "# Generated module classes, non-fast-path, compile with low/medium optimization\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_CLASSES_SLOW", cmake_list(classes_slow));
|
2019-10-17 23:44:10 +00:00
|
|
|
*of << "# Generated module classes, fast-path, compile with highest optimization\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_CLASSES_FAST", cmake_list(classes_fast));
|
2020-04-15 11:58:34 +00:00
|
|
|
*of << "# Generated support classes, non-fast-path, compile with "
|
|
|
|
"low/medium optimization\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_SUPPORT_SLOW", cmake_list(support_slow));
|
2019-10-17 23:44:10 +00:00
|
|
|
*of << "# Generated support classes, fast-path, compile with highest optimization\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_SUPPORT_FAST", cmake_list(support_fast));
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
*of << "# All dependencies\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_DEPS", cmake_list(V3File::getAllDeps()));
|
2019-10-17 23:44:10 +00:00
|
|
|
|
|
|
|
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
|
2022-11-20 15:25:41 +00:00
|
|
|
cmake_set_raw(*of, name + "_USER_CLASSES", cmake_list(v3Global.opt.cppFiles()));
|
2021-11-26 22:55:36 +00:00
|
|
|
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
|
2020-08-15 13:43:53 +00:00
|
|
|
*of << "# Verilate hierarchical blocks\n";
|
|
|
|
// Sorted hierarchical blocks in order of leaf-first.
|
|
|
|
const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted();
|
2020-09-19 22:48:05 +00:00
|
|
|
*of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n";
|
2020-08-15 13:43:53 +00:00
|
|
|
for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin();
|
|
|
|
it != hierBlocks.end(); ++it) {
|
|
|
|
const V3HierBlock* hblockp = *it;
|
|
|
|
const V3HierBlock::HierBlockSet& children = hblockp->children();
|
|
|
|
const string prefix = hblockp->hierPrefix();
|
|
|
|
*of << "add_library(" << prefix << " STATIC)\n";
|
2020-09-19 22:48:05 +00:00
|
|
|
*of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n";
|
2020-08-15 13:43:53 +00:00
|
|
|
if (!children.empty()) {
|
|
|
|
*of << "target_link_libraries(" << prefix << " INTERFACE";
|
2022-07-30 14:01:25 +00:00
|
|
|
for (const auto& childr : children) { *of << " " << (childr)->hierPrefix(); }
|
2020-08-15 13:43:53 +00:00
|
|
|
*of << ")\n";
|
|
|
|
}
|
|
|
|
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
|
|
|
|
<< hblockp->modp()->name() << " DIRECTORY "
|
2022-11-20 15:25:41 +00:00
|
|
|
<< v3Global.opt.makeDir() + "/" + prefix << " SOURCES ";
|
2022-07-30 14:01:25 +00:00
|
|
|
for (const auto& childr : children) {
|
2022-11-20 15:26:23 +00:00
|
|
|
*of << " " << v3Global.opt.makeDir() + "/" + childr->hierWrapper(true);
|
2020-08-15 13:43:53 +00:00
|
|
|
}
|
|
|
|
*of << " ";
|
2020-09-18 23:13:49 +00:00
|
|
|
const string vFile = hblockp->vFileIfNecessary();
|
|
|
|
if (!vFile.empty()) *of << vFile << " ";
|
2020-08-15 13:43:53 +00:00
|
|
|
const V3StringList& vFiles = v3Global.opt.vFiles();
|
2020-09-19 22:48:05 +00:00
|
|
|
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
|
2020-08-15 13:43:53 +00:00
|
|
|
*of << " VERILATOR_ARGS ";
|
2022-11-20 15:25:41 +00:00
|
|
|
*of << "-f " << hblockp->commandArgsFileName(true)
|
2020-08-15 13:43:53 +00:00
|
|
|
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
|
|
|
|
// with .so
|
|
|
|
<< ")\n";
|
|
|
|
}
|
2021-11-14 14:39:31 +00:00
|
|
|
*of << "\n# Verilate the top module that refers to lib-create wrappers of above\n";
|
2020-09-19 22:48:05 +00:00
|
|
|
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
|
|
|
|
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
|
2022-11-20 15:25:41 +00:00
|
|
|
<< v3Global.opt.makeDir() << " SOURCES ";
|
2020-11-11 03:10:38 +00:00
|
|
|
for (const auto& itr : *planp) {
|
2022-11-20 15:26:23 +00:00
|
|
|
*of << " " << v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true);
|
2020-08-15 13:43:53 +00:00
|
|
|
}
|
2022-11-20 15:25:41 +00:00
|
|
|
*of << " " << cmake_list(v3Global.opt.vFiles());
|
2020-08-15 13:43:53 +00:00
|
|
|
*of << " VERILATOR_ARGS ";
|
2022-11-20 15:25:41 +00:00
|
|
|
*of << "-f " << planp->topCommandArgsFileName(true);
|
2020-08-15 13:43:53 +00:00
|
|
|
*of << ")\n";
|
|
|
|
}
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|
2020-04-15 11:58:34 +00:00
|
|
|
|
2019-10-17 23:44:10 +00:00
|
|
|
public:
|
2020-04-15 11:58:34 +00:00
|
|
|
explicit CMakeEmitter() { emitOverallCMake(); }
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~CMakeEmitter() = default;
|
2019-10-17 23:44:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void V3EmitCMake::emit() {
|
2020-04-15 11:58:34 +00:00
|
|
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
2021-11-26 22:55:36 +00:00
|
|
|
const CMakeEmitter emitter;
|
2019-10-17 23:44:10 +00:00
|
|
|
}
|