Cmake如何编译和链接静态成员函数

问题描述 投票:0回答:1

这是我的代码'main.cpp',我想编译它:

#include <cstdio>

#include "lexer.h"
#include "parser.h"

auto main() -> int {

  Parser::binop_precedence = {{'<', 10}, {'+', 20}, {'-', 20}, {'*', 40}};

  fprintf(stderr, "ready> ");
  Lexer::GetNextToken();

  Parser::MainLoop();

  return 0;
}

“parse.h”代码如下:

#include <cstdio>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "AST.h"
#include "lexer.h"
class Parser {
public:
  // numberexpr ::= number
  static auto ParseNumberExpr() -> std::unique_ptr<ExprAST> {
    auto result = std::make_unique<NumberExprAST>(Lexer::num_val);
    Lexer::GetNextToken();
    return std::move(result);
  }

  static auto ParseExpression() -> std::unique_ptr<ExprAST> {
    auto lhs = ParsePrimary();
    if (lhs == nullptr) {
      return nullptr;
    }
    return ParseBinOpRhs(0, std::move(lhs));
  }
  
  static auto ParseParenExpr() -> std::unique_ptr<ExprAST> {
    Lexer::GetNextToken();  
    auto v = ParseExpression();
    if (v == nullptr) {
      return nullptr;
    }
    if (Lexer::cur_tok != ')') {
      return LogError("expected ')'");
    }
    Lexer::GetNextToken();  
    return v;
  }

  static auto ParseIdentifierExpr() -> std::unique_ptr<ExprAST> {
    std::string id_name = Lexer::identifier_str;
    Lexer::GetNextToken();
    if (Lexer::cur_tok != '(') {
      return std::make_unique<VariableExprAST>(id_name);
    }
    Lexer::GetNextToken(); 
    std::vector<std::unique_ptr<ExprAST>> args;
    if (Lexer::cur_tok != ')') {
      while(true) {
        if (auto arg = ParseExpression()) {
          args.push_back(std::move(arg));
        } else {
          return nullptr;
        }
        if (Lexer::cur_tok == ')') {
          break;
        }
        if (Lexer::cur_tok != ',') {
          return LogError("Expected ')' or ',' in argument list");
        }
        Lexer::GetNextToken();
      }
    }
    Lexer::GetNextToken(); 
    return std::make_unique<CallExprAST>(id_name, std::move(args));
  }

  static auto ParsePrimary() -> std::unique_ptr<ExprAST> {
    switch (Lexer::cur_tok) {
      default:
        return LogError("unknown token when expecting an expression");
      case Token::tok_identifier:
        return ParseIdentifierExpr();
      case Token::tok_number:
        return ParseNumberExpr();
      case '(' :
        return ParseParenExpr();
    }
  } 
public:
  // static std::map<char, int> binop_precedence = {{'<', 10}, {'+', 20}, {'-', 20}, {'*', 40}};
  static std::map<char, int> binop_precedence;
};

lexer.h
文件如下:

class Lexer {
public:
  /// gettok Return the next toker from standard input
  static auto GetTok() -> int {
    static int last_char = ' ';
    // Skip any whitespace
    while(std::isspace(last_char) != 0) {
      last_char = getchar();
    }
    if (std::isalpha(last_char) != 0) {
      identifier_str += std::to_string(last_char);
      while(std::isalnum(last_char = getchar()) != 0) {
        identifier_str += std::to_string(last_char);
      }
      if (identifier_str == "def") {
        return Token::tok_def;
      }
      if (identifier_str == "extern") {
        return Token::tok_extern;
      }
      return Token::tok_identifier;
    }
    if ((std::isdigit(last_char) != 0) || last_char == '.') {
      std::string num_str;
      do {
      num_str += std::to_string(last_char);
      last_char = getchar();
      }while ((std::isdigit(last_char) != 0) || last_char == '.');

      num_val = std::strtod(num_str.c_str(), nullptr);
      return Token::tok_number;
    }
    // 处理注释
    if (last_char == '#') {
      do {
        last_char = getchar();
      }while(last_char != EOF && last_char != '\n' && last_char != '\r');
      if (last_char != EOF) {
        return GetTok();
      }
    }
    if (last_char == EOF) {
      return Token::tok_eof;
    }
    int this_char = last_char;
    last_char = getchar();
    return this_char;
  }

  static auto GetNextToken() -> int {
    return cur_tok = Lexer::GetTok();
  }

public:
  static std::string identifier_str;   // Filled in if tok_identifier
  static double num_val; // Filled in tok_number
  static int cur_tok;
};

我想使用cmake来编译

main.cpp
并链接
parse.h
文件。我的
CMakeLists.txt
是这样的:

cmake_minimum_required(VERSION 3.10)

set (CMAKE_CXX_FLAGS -std=c++20)
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for clangd
set(CMAKE_CXX_STANDARD 20)  # compile as C++20
set(CMAKE_CXX_STANDARD_REQUIRED 20) # require C++20 support

project(Kaleidoscope)

message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
message(STATUS "CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_FXX_FLAGS_DEBUG}")

# includes
set(KALEDIOSCOPE_SRC_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)

include_directories(${KALEDIOSCOPE_SRC_INCLUDE_DIR})

SET(KALEIDOSCOPE_LIBS log)

add_executable(Kaleidoscope src/lexer.cpp src/parse.cpp src/log.cpp src/main.cpp)

target_include_directories(Kaleidoscope PRIVATE ${PROJECT_SOURCE_DIR}/include)
 

当我编译它时,编译器告诉我

/usr/bin/ld: CMakeFiles/Kaleidoscope.dir/src/main.cpp.o: in function `main':
main.cpp:(.text+0x56): undefined reference to `Parser::binop_precedence'
/usr/bin/ld: CMakeFiles/Kaleidoscope.dir/src/main.cpp.o: in function `Lexer::GetNextToken()':
main.cpp:(.text._ZN5Lexer12GetNextTokenEv[_ZN5Lexer12GetNextTokenEv]+0xc): undefined reference to `Lexer::cur_tok'
/usr/bin/ld: CMakeFiles/Kaleidoscope.dir/src/main.cpp.o: in function `Parser::MainLoop()':
main.cpp:(.text._ZN6Parser8MainLoopEv[_ZN6Parser8MainLoopEv]+0x28): undefined reference to `Lexer::cur_tok'
/usr/bin/ld: CMakeFiles/Kaleidoscope.dir/src/main.cpp.o: in function `Lexer::GetTok()':
main.cpp:(.text._ZN5Lexer6GetTokEv[_ZN5Lexer6GetTokEv]+0x63): undefined reference to `Lexer::identifier_str[abi:cxx11]'
/usr/bin/ld: main.cpp:(.text._ZN5Lexer6GetTokEv[_ZN5Lexer6GetTokEv]+0xb5): undefined reference to `Lexer::identifier_str[abi:cxx11]'
/usr/bin/ld: main.cpp:(.text._ZN5Lexer6GetTokEv[_ZN5Lexer6GetTokEv]+0x108): undefined reference to `Lexer::identifier_str[abi:cxx11]'
/usr/bin/ld: main.cpp:(.text._ZN5Lexer6GetTokEv[_ZN5Lexer6GetTokEv]+0x134): undefined reference to `Lexer::identifier_str[abi:cxx11]'
/usr/bin/ld: main.cpp:(.text._ZN5Lexer6GetTokEv[_ZN5Lexer6GetTokEv]+0x23b): undefined reference to `Lexer::num_val'
/usr/bin/ld: CMakeFiles/Kaleidoscope.dir/src/main.cpp.o: in function `Parser::ParsePrototype()':
main.cpp:(.text._ZN6Parser14ParsePrototypeEv[_ZN6Parser14ParsePrototypeEv]+0x1a): undefined reference to `Lexer::cur_tok'
/usr/bin/ld: main.cpp:
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [CMakeFiles/Kaleidoscope.dir/build.make:145: Kaleidoscope] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/Kaleidoscope.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

我想知道如何编写CMakeLists.txt来处理这个问题。谢谢!

c++ cmake
1个回答
0
投票

您正在引用

Parser::binop_precedence
而没有它的实例。

您需要在全局命名空间中创建实例,最好是在

parse.cpp
中:

std::map<char, int> Parser::binop_precedence;
© www.soinside.com 2019 - 2024. All rights reserved.