diff --git a/recipes/llvm/all/conandata.yml b/recipes/llvm/all/conandata.yml new file mode 100644 index 0000000000000..b202fb92082f1 --- /dev/null +++ b/recipes/llvm/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + 10.0.0: + url: https://github.com/llvm/llvm-project/archive/llvmorg-10.0.0.zip + sha256: d2fadc9962ccceab2b9b0d806352db690c9040f24f4a4bdef37b72dcc82fc07a diff --git a/recipes/llvm/all/conanfile.py b/recipes/llvm/all/conanfile.py new file mode 100644 index 0000000000000..e176a2df8f8ed --- /dev/null +++ b/recipes/llvm/all/conanfile.py @@ -0,0 +1,113 @@ +from conans import ConanFile, tools, CMake +from conans.tools import Version +from conans.errors import ConanInvalidConfiguration +import os, shutil, glob + +projects = [ + 'clang', + 'clang-tools-extra', + 'compiler-rt', + 'debuginfo-tests', + 'libc', + 'libclc', + 'libcxx', + 'libcxxabi', + 'libunwind', + 'lld', + 'lldb', + 'mlir', + 'openmp', + 'parallel-libs', + 'polly', + 'pstl' +] + +default_projects = [ + 'clang', + 'compiler-rt' +] + +class Llvm(ConanFile): + name = 'llvm' + description = 'The LLVM Project is a collection of modular and reusable compiler and toolchain technologies' + url = 'https://github.com/conan-io/conan-center-index' + homepage = 'https://github.com/llvm/llvm-project' + license = 'Apache 2.0' + topics = 'c++', 'compiler', 'tooling' + + settings = 'os', 'arch', 'compiler', 'build_type' + + no_copy_source = True + _source_subfolder = 'source_subfolder' + + options = {**{ 'with_' + project : [True, False] for project in projects }, **{ + 'fPIC': [True, False] + }} + default_options = {**{ 'with_' + project : project in default_projects for project in projects }, **{ + 'fPIC': True + }} + generators = 'cmake_find_package' + + @property + def repo_folder(self): + return os.path.join(self.source_folder, self._source_subfolder) + + def project_folder(self, project): + return os.path.join(self.repo_folder, project) + + def source(self): + tools.get(**self.conan_data["sources"][self.version]) + extracted_dir = 'llvm-project-llvmorg-' + self.version + os.rename(extracted_dir, self._source_subfolder) + + def configure(self): + if self.settings.compiler.get_safe("cppstd"): + tools.check_min_cppstd(self, '14') + + if self.settings.compiler == "Visual Studio" and Version(self.settings.compiler.version) < "19.1": + raise ConanInvalidConfiguration("Need MSVC >= 19.1") + + def build(self): + enabled_projects = [project for project in projects if getattr(self.options, 'with_' + project)] + self.output.info('Enabled LLVM subprojects: {}'.format(', '.join(enabled_projects))) + + cmake = CMake(self); + cmake.configure( + defs = { + 'LLVM_ENABLE_PROJECTS': ';'.join(enabled_projects) + }, + source_folder = os.path.join(self._source_subfolder, 'llvm') + ) + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + self.copy( + 'LICENSE.TXT', + src=self.project_folder('clang'), + dst='licenses', + keep_path=False) + + ignore = [ + 'share', + 'libexec', + '**/Find*.cmake', + '**/*Config.cmake' + ] + + for ignore_entry in ignore: + ignore_glob = os.path.join(self.package_folder, ignore_entry) + + for ignore_path in glob.glob(ignore_glob, recursive=True): + self.output.info('Remove ignored file/directory "{}" from package'.format(ignore_path)) + + if os.path.isfile(ignore_path): + os.remove(ignore_path) + else: + shutil.rmtree(ignore_path) + + def package_info(self): + self.cpp_info.libs = tools.collect_libs(self) + self.cpp_info.builddirs = ['lib/cmake'] diff --git a/recipes/llvm/all/test_package/CMakeLists.txt b/recipes/llvm/all/test_package/CMakeLists.txt new file mode 100644 index 0000000000000..6d70aefb6c065 --- /dev/null +++ b/recipes/llvm/all/test_package/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.1) +project(test_package) + +set(CMAKE_CXX_STANDARD 14) + +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +conan_basic_setup() + +add_executable(${PROJECT_NAME} test_package.cpp) +target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) diff --git a/recipes/llvm/all/test_package/conanfile.py b/recipes/llvm/all/test_package/conanfile.py new file mode 100644 index 0000000000000..bd7165a553cf4 --- /dev/null +++ b/recipes/llvm/all/test_package/conanfile.py @@ -0,0 +1,17 @@ +from conans import ConanFile, CMake, tools +import os + + +class TestPackageConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if not tools.cross_building(self.settings): + bin_path = os.path.join("bin", "test_package") + self.run(bin_path, run_environment=True) diff --git a/recipes/llvm/all/test_package/test_package.cpp b/recipes/llvm/all/test_package/test_package.cpp new file mode 100644 index 0000000000000..03bd7c44d9349 --- /dev/null +++ b/recipes/llvm/all/test_package/test_package.cpp @@ -0,0 +1,452 @@ +// Kaleidoscope example from https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html#full-code-listing + +#include "llvm/ADT/STLExtras.h" +#include +#include +#include +#include +#include +#include +#include +#include + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// + +namespace { + +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() = default; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes). +class PrototypeAST { + std::string Name; + std::vector Args; + +public: + PrototypeAST(const std::string &Name, std::vector Args) + : Name(Name), Args(std::move(Args)) {} + + const std::string &getName() const { return Name; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = std::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return std::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return std::make_unique(IdName, std::move(Args)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + } +} + +/// binoprhs +/// ::= ('+' primary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the primary expression after the binary operator. + auto RHS = ParsePrimary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = std::make_unique(BinOp, std::move(LHS), + std::move(RHS)); + } +} + +/// expression +/// ::= primary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParsePrimary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +static std::unique_ptr ParsePrototype() { + if (CurTok != tok_identifier) + return LogErrorP("Expected function name in prototype"); + + std::string FnName = IdentifierStr; + getNextToken(); + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + return std::make_unique(FnName, std::move(ArgNames)); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return std::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = std::make_unique("__anon_expr", + std::vector()); + return std::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing +//===----------------------------------------------------------------------===// + +static void HandleDefinition() { + if (ParseDefinition()) { + fprintf(stderr, "Parsed a function definition.\n"); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (ParseExtern()) { + fprintf(stderr, "Parsed an extern\n"); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (ParseTopLevelExpr()) { + fprintf(stderr, "Parsed a top-level expr\n"); + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + return 0; // Return to make conan test_package continue + // (The example is interactive) + + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + // Run the main "interpreter loop" now. + MainLoop(); + + return 0; +} diff --git a/recipes/llvm/config.yml b/recipes/llvm/config.yml new file mode 100644 index 0000000000000..9cf37bae8e00d --- /dev/null +++ b/recipes/llvm/config.yml @@ -0,0 +1,3 @@ +versions: + 10.0.0: + folder: all