手寫g++編譯命令行工具筆記
基本想法
為什么要寫 CPPRUN:
- 如果要開警告開關,敲完整的編譯代碼還挺麻煩的
- 想要編譯與運行一次性完成
- Windows 的控制臺本來是 cmd,后來有了 Powershell,但是后者不能用
<指定輸入文件,比較麻煩
所以可以直接用 C++ 寫一個類似于腳本的命令行程序。
功能
- 編譯單個源代碼。
- 默認情況下若編譯成功,則運行程序,可以指定輸入輸出文件。
- 毫秒級計算實際運行時間。
基本用法:
.\run <源程序文件名,不包括.cpp擴展> <其他指令>
指令列表:
\i <文件名>指定輸入文件\o <文件名>指定輸出文件\f <文件名,不帶擴展名>指定exe文件名,默認與源文件相同\std <c++/c++11/c++14>設置C++版本,默認 C++14\u取消警告,默認開啟-Wall -Wextra -Wconversion -Wshadow\cmd回顯編譯命令,默認不開啟\comp只編譯不運行,默認編譯后立即運行
代碼實現
命令行程序添加參數
以 CPPRUN 為例,.\run <...> 中的 <...> 就是參數。在 C++ 中 main 函數其實是有兩個參數的(只是競賽的時候從來不會用到,也可以不寫),即
// 參數隨便命名,這里舉個例子
int main(int argc, char** argv) {
}
其中 argc 是 ”參數數量“ + 1,注意命令行中不同參數用若干空格隔開;argv[1 ~ argc - 1] 是字符串形式的參數。
在程序中形成編譯命令并執行
C風格字符串的拼接還挺麻煩,可以直接用 iostream 中的 string,通過 +, += 可以完成字符串與字符、字符串與字符串的拼接。
執行需要用到 system 函數,但是 system 的參數是C風格字符串,string 類型需要用到內置的 c_str() 轉化。另外一提,在 system 中是可以使用 <, > 指定輸入輸出文件的,因為其本質是在 cmd 中執行了指令。相當于免去了在 Powershell 中打開 cmd 執行指令再關閉 cmd 的這種繁瑣的操作。
system 函數是有返回值的,就是執行的該條指令的返回值。這樣可以獲取程序的返回值判斷程序是否正常結束,也可以通過 g++ 的返回值判斷是否有編譯錯誤。
Tab. g++ 返回 0 是編譯成功(包括有編譯警告),其余返回值是有編譯錯誤。
其他的小細節
如果想要在命令行中輸出中文,一定保證你的源文件是在 GBK(或者其他中文) 的編碼下編寫并保存的!
源代碼
/* Lucky_Glass */
// 2022-6-21 modified
#include <windows.h>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <iostream>
int getOption(char *_str) {
std::string str(_str);
if (str == "\\i") return 1;
if (str == "\\o") return 2;
if (str == "\\f") return 3;
if (str == "\\std") return 4;
if (str == "\\u") return 5;
if (str == "\\cmd") return 6;
if (str == "\\comp") return 7;
return 0;
}
void somethingError() {
std::cerr << "<fail> CPPRUN發生了未知錯誤" << std::endl;
exit(1);
}
bool isopt[50];
int main(int num, char *opt[]) {
std::string cmd("g++ ");
if (num == 1) {
std::cerr << "<fail> 請指定編譯文件" << std::endl;
return 0;
}
std::string fil(opt[1]), inp, oup, gver("c++14");
cmd += fil, cmd += ".cpp";
for (int i = 2; i < num; ++i) {
int optid = getOption(opt[i]);
isopt[optid] = true;
if (optid <= 4) {
std::string ext(opt[++i]);
switch (optid) {
case 1: inp = ext; break;
case 2: oup = ext; break;
case 3: fil = ext; break;
case 4: gver = ext; break;
default: somethingError();
}
}
}
cmd += " -o ", cmd += fil;
if (gver == "c++14") cmd += " -std=c++14";
else if (gver == "c++11") cmd += " -std=c++11";
else if (gver != "c++") {
std::cerr << "<fail> C++版本只能為 c++/c++11/c++14" << std::endl;
return 0;
}
if (!isopt[5])
cmd += " -Wall -Wextra -Wconversion -Wshadow";
if (isopt[6])
std::cerr << cmd << std::endl;
if(!system(cmd.c_str()))
std::cerr << "<success> 編譯完成" << std::endl;
else {
std::cerr << "<fail> 編譯失敗" << std::endl;
return 0;
}
if (!isopt[7]) {
cmd = ".\\", cmd += fil, cmd += ".exe";
if (isopt[1]) cmd += " < ", cmd += inp;
if (isopt[2]) cmd += " > ", cmd += oup;
DWORD stt, edt;
stt = GetTickCount();
int ret = system(cmd.c_str());
edt = GetTickCount();
std::cerr.precision(3);
std::cerr << "<success> 運行結束,返回值 " << ret
<< ",運行時間 " << (edt - stt) / 1000.0
<< std::endl;
}
return 0;
}
THE END
歡迎轉載?(?????)?,請在轉載文章末尾附上原博文網址~

浙公網安備 33010602011771號