// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: Emit CMake file list // // Code available from: https://verilator.org // //************************************************************************* // // Copyright 2004-2019 by Wilson Snyder. This program is free software; you can // redistribute it and/or modify it under the terms of either the GNU // Lesser General Public License Version 3 or the Perl Artistic License // Version 2.0. // // Verilator is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // //************************************************************************* #include "config_build.h" #include "verilatedos.h" #include "V3Global.h" #include "V3Os.h" #include "V3EmitCMake.h" #include "V3EmitCBase.h" #include //###################################################################### // Emit statements class CMakeEmitter { // METHODS VL_DEBUG_FUNC; // Declare debug() // STATIC FUNCTIONS // Concatenate all strings in 'strs' with ' ' between them. template static string cmake_list(const List& strs) { string s; if (strs.begin() != strs.end()) { s.append("\""); s.append(*strs.begin()); s.append("\""); for (typename List::const_iterator it = ++strs.begin(); it != strs.end(); ++it) { s.append(" \""); s.append(*it); 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, const string& cache_type = "", const string& docstring = "") { of << "set(" << name << " " << raw_value; if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; } of << ")\n"; } static void cmake_set(std::ofstream& of, const string& name, const string& value, const string& cache_type = "", const string& docstring = "") { string raw_value = "\"" + value + "\""; cmake_set_raw(of, name, raw_value, cache_type, docstring); } //Swap all backslashes for forward slashes, because of Windows static string deslash(const string& s) { std::string res = s; for (string::iterator it = res.begin(); it != res.end(); ++it) { if (*it == '\\') *it = '/'; } return res; } static void emitOverallCMake() { const vl_unique_ptr of (V3File::new_ofstream(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".cmake")); string name = v3Global.opt.prefix(); *of << "# Verilated -*- CMake -*-\n"; *of << "# DESCR" "IPTION: Verilator output: CMake include script with class lists\n"; *of << "#\n"; *of << "# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n"; *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"; cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), "FILEPATH", "Perl executable (from $PERL)"); cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), "PATH", "Path to Verilator kit (from $VERILATOR_ROOT)"); *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"; cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage()?"1":"0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))?"1":"0"); *of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n"; cmake_set_raw(*of, name + "_TRACE_FST", (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) ? "1":"0"); *of << "\n### Sources...\n"; std::vector classes_fast, classes_slow, support_fast, support_slow, global; for (AstFile* nodep = v3Global.rootp()->filesp(); nodep; nodep = VN_CAST(nodep->nextp(), File)) { AstCFile* cfilep = VN_CAST(nodep, CFile); 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()); } } } } global.push_back("${VERILATOR_ROOT}/include/verilated.cpp"); if (v3Global.dpi()) { global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp"); } if (v3Global.opt.vpi()) { global.push_back("${VERILATOR_ROOT}/include/verilated_vpi.cpp"); } if (v3Global.opt.savable()) { global.push_back("${VERILATOR_ROOT}/include/verilated_save.cpp"); } if (v3Global.opt.coverage()) { global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp"); } if (v3Global.opt.trace()) { global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceName()+"_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { v3error("Unsupported: This trace format is not supported in SystemC, use VCD format."); } global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceName()+"_sc.cpp"); } } if (v3Global.opt.mtasks()) { global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); } if (!v3Global.opt.protectLib().empty()) { global.push_back(v3Global.opt.makeDir()+"/"+v3Global.opt.protectLib()+".cpp"); } *of << "# Global classes, need linked once per executable\n"; cmake_set_raw(*of, name + "_GLOBAL", deslash(cmake_list(global))); *of << "# Generated module classes, non-fast-path, compile with low/medium optimization\n"; cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow))); *of << "# Generated module classes, fast-path, compile with highest optimization\n"; cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast))); *of << "# Generated support classes, non-fast-path, compile with low/medium optimization\n"; cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow))); *of << "# Generated support classes, fast-path, compile with highest optimization\n"; cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast))); *of << "# All dependencies\n"; cmake_set_raw(*of, name + "_DEPS", deslash(cmake_list(V3File::getAllDeps()))); *of << "# User .cpp files (from .cpp's on Verilator command line)\n"; cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles()))); } public: explicit CMakeEmitter() { emitOverallCMake(); } virtual ~CMakeEmitter() {} }; void V3EmitCMake::emit() { UINFO(2,__FUNCTION__<<": "<