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 }