github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/cmd/nasir/main.cpp (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  
    21  #include "common/byte.h"
    22  #include "common/ir_conf_reader.h"
    23  #include "fs/proto/ir.pb.h"
    24  #include "fs/util.h"
    25  #include "util/command.h"
    26  #include <algorithm>
    27  #include <boost/format.hpp>
    28  #include <boost/process.hpp>
    29  #include <boost/program_options.hpp>
    30  #include <fstream>
    31  #include <iostream>
    32  
    33  namespace po = boost::program_options;
    34  namespace bp = boost::process;
    35  
    36  std::string root_path = "";
    37  
    38  typedef struct clang_flags_t {
    39    std::string root_path;
    40    std::string flag_command;
    41  }clang_flags;
    42  
    43  void merge_clang_arguments(const std::vector<std::string> &flag_value_list,
    44                             const clang_flags &flags,
    45                             std::string &command_string) {
    46    if (!flag_value_list.empty()) {
    47      std::for_each(
    48          flag_value_list.begin(), flag_value_list.end(),
    49          [&command_string, &flags](const std::string &value) {
    50            bool is_add_root_path = !neb::fs::is_absolute_path(value);
    51            command_string = command_string + flags.flag_command;
    52            if (is_add_root_path) {
    53              command_string = command_string +
    54                               neb::fs::join_path(flags.root_path, value) + " ";
    55            } else {
    56              command_string = command_string + value + " ";
    57            }
    58          });
    59    }
    60  }
    61  
    62  int execute_command(const std::string &command_string) {
    63    bp::ipstream pipe_stream;
    64    bp::child c(command_string, bp::std_out > pipe_stream);
    65  
    66    std::string line;
    67    while(pipe_stream && std::getline(pipe_stream, line) && !line.empty()) {
    68      std::cerr << line << std::endl;
    69    }
    70  
    71    c.wait();
    72    return c.exit_code();
    73  }
    74  
    75  void make_ir_bitcode(neb::ir_conf_reader &reader, std::string &ir_bc_file, bool isPayload) {
    76    int result = -1;
    77  
    78    std::string current_path = neb::fs::cur_dir();
    79    std::string command_string(
    80        neb::fs::join_path(current_path, "lib_llvm/bin/clang") +
    81        " -O2 -emit-llvm ");
    82  
    83    clang_flags flags;
    84  
    85    flags.flag_command = "";
    86    merge_clang_arguments(reader.flags(), flags, command_string);
    87  
    88    flags.root_path = root_path;
    89    // flags.root_path = reader.root_path();
    90    flags.flag_command = " -I";
    91    merge_clang_arguments(reader.include_header_files(), flags, command_string);
    92  
    93    flags.flag_command = " -L";
    94    merge_clang_arguments(reader.link_path(), flags, command_string);
    95  
    96    flags.flag_command = " -l";
    97    merge_clang_arguments(reader.link_files(), flags, command_string);
    98  
    99    flags.flag_command = " -c ";
   100    merge_clang_arguments(reader.cpp_files(), flags, command_string);
   101  
   102    if (isPayload) {
   103      std::string temp_path = neb::fs::tmp_dir();
   104      ir_bc_file = neb::fs::join_path(temp_path, reader.self_ref().name() + "_ir.bc");
   105    }
   106  
   107    command_string += " -o " + ir_bc_file;
   108    std::cout << command_string << std::endl;
   109    LOG(INFO) << command_string;
   110  
   111    result = neb::util::command_executor::execute_command(command_string);
   112    if (result != 0) {
   113      LOG(INFO) << "error: executed by boost::process::system.";
   114      LOG(INFO) << "result code = " << result;
   115      exit(1);
   116    }
   117  }
   118  
   119  po::variables_map get_variables_map(int argc, char *argv[]) {
   120    po::options_description desc("Generate IR Payload");
   121    desc.add_options()("help", "show help message")(
   122        "input", po::value<std::string>(), "IR configuration file")(
   123        "output", po::value<std::string>(),
   124        "output file")("mode", po::value<std::string>()->default_value("payload"),
   125                       "Generate ir bitcode or ir payload. - [bitcode | "
   126                       "payload], default:payload");
   127  
   128    po::variables_map vm;
   129    po::store(po::parse_command_line(argc, argv, desc), vm);
   130    po::notify(vm);
   131    if (vm.count("help")) {
   132      std::cout << desc << "\n";
   133      exit(1);
   134    }
   135  
   136    if (!vm.count("input")) {
   137      std::cout << "You must specify \"input\"!";
   138      exit(1);
   139    }
   140    if (vm.count("mode")) {
   141      std::string m = vm["mode"].as<std::string>();
   142      if (m != "bitcode" && m != "payload") {
   143        std::cout << "Wrong mode, should be either bitcode or payload."
   144                  << std::endl;
   145        exit(1);
   146      }
   147    }
   148    if (!vm.count("output")) {
   149      std::cout << "You must specify output!";
   150      exit(1);
   151    }
   152  
   153    return vm;
   154  }
   155  
   156  void make_ir_payload(std::ifstream &ifs,
   157      const neb::ir_conf_reader &reader,
   158      const std::string &ir_bc_file,
   159      const std::string &output_file
   160      ) {
   161    ifs.open(ir_bc_file.c_str(), std::ios::in | std::ios::binary);
   162    if (!ifs.is_open()) {
   163      throw std::invalid_argument(
   164          boost::str(boost::format("can't open file %1%") % ir_bc_file));
   165    }
   166  
   167    ifs.seekg(0, ifs.end);
   168    std::ifstream::pos_type size = ifs.tellg();
   169    if (size > 128 * 1024) {
   170      throw std::invalid_argument("IR file too large!");
   171    }
   172  
   173    neb::bytes buf(size);
   174  
   175    ifs.seekg(0, ifs.beg);
   176    ifs.read((char *)buf.value(), buf.size());
   177    if (!ifs)
   178      throw std::invalid_argument(boost::str(
   179            boost::format("Read IR file error: only %1% could be read") %
   180            ifs.gcount()));
   181  
   182    nbre::NBREIR ir_info;
   183    ir_info.set_name(reader.self_ref().name());
   184    ir_info.set_version(reader.self_ref().version().data());
   185    ir_info.set_height(reader.available_height());
   186    for (size_t i = 0; i < reader.depends().size(); ++i) {
   187      nbre::NBREIRDepend *d = ir_info.add_depends();
   188      d->set_name(reader.depends()[i].name());
   189      d->set_version(reader.depends()[i].version().data());
   190    }
   191    ir_info.set_ir(neb::byte_to_string(buf));
   192    ir_info.set_ir_type(neb::ir_type::cpp);
   193  
   194    auto bytes_long = ir_info.ByteSizeLong();
   195    if (bytes_long > 128 * 1024) {
   196      throw std::invalid_argument("bytes too long !");
   197    }
   198  
   199    std::ofstream ofs;
   200    ofs.open(output_file,
   201        std::ios::out | std::ios::binary | std::ios::trunc);
   202    if (!ofs.is_open()) {
   203      throw std::invalid_argument("can't open output file");
   204    }
   205    neb::bytes out_bytes(bytes_long);
   206    ir_info.SerializeToArray((void *)out_bytes.value(), out_bytes.size());
   207  
   208    std::string out_base64 = out_bytes.to_base64();
   209    LOG(INFO) << out_base64;
   210  
   211    ofs.write(out_base64.c_str(), out_base64.size());
   212    ofs.close();
   213  }
   214  
   215  int main(int argc, char *argv[]) {
   216    ::google::InitGoogleLogging(argv[0]);
   217    po::variables_map vm = get_variables_map(argc, argv);
   218    std::ifstream ifs;
   219  
   220    std::string root_dir = "";
   221    try {
   222      std::string ir_fp = vm["input"].as<std::string>();
   223      neb::ir_conf_reader reader(ir_fp);
   224  
   225      root_dir = neb::fs::join_path(neb::fs::cur_full_path(), ir_fp);
   226      root_dir = neb::fs::parent_dir(root_dir);
   227      LOG(INFO) << "root path: " << root_dir;
   228      root_path = root_dir;
   229  
   230      std::string mode = vm["mode"].as<std::string>();
   231      std::string ir_bc_file;
   232  
   233      if (mode == "payload") {
   234        LOG(INFO) << "mode paylaod";
   235        make_ir_bitcode(reader, ir_bc_file, true);
   236        if (!neb::fs::exists(ir_bc_file)) {
   237          std::cout << "cann't compile the file " << std::endl;
   238          exit(-1);
   239        }
   240        if (reader.cpp_files().size() > 1) {
   241          std::cout
   242              << "\t**Too many cpp files, we only support 1 cpp file for now."
   243              << std::endl;
   244          return -1;
   245        }
   246        std::string cpp_fp = reader.cpp_files()[0];
   247        cpp_fp = neb::fs::join_path(root_dir, cpp_fp);
   248        make_ir_payload(ifs, reader, cpp_fp, vm["output"].as<std::string>());
   249        execute_command("rm -f " + ir_bc_file);
   250      } else if (mode == "bitcode") {
   251        ir_bc_file = vm["output"].as<std::string>();
   252        make_ir_bitcode(reader, ir_bc_file, false);
   253      } else {
   254        throw std::logic_error("unexpected mode ");
   255        return 1;
   256      }
   257    } catch (std::exception &e) {
   258      ifs.close();
   259      std::cout << e.what() << std::endl;
   260    }
   261    return 0;
   262  }