C ++ 내부에서 외부 파일 실행

Aug 21 2020

프런트 엔드에서 사용자에게 코드를 입력 할 수있는 텍스트 편집기를 제공하는 응용 프로그램을 만들려고 한 다음 해당 코드를 실행하고 결과를 반환합니다. 나만의 leetcode 버전을 학습 프로젝트로 빌드하는 것이 재미있는 프로젝트라고 생각했습니다.

지금은 제공된 코드를 실행하기 위해 수행하는 작업입니다. 내가 지금 구현 한 전부이기 때문에 우리가 파이썬 코드를 실행하고 있다고 가정 해 봅시다.

먼저 사용자가 제출 한 코드를 가져와 주어진 코드가 포함 된 파일을 만듭니다.

std::string python(std::string code){
    std::string langCommand = "python3 ";
    std::string outFile;

    //I am hoping to parallelize this operation so I add threadID to output
    outFile = createOutFileName("PythonRunner.py");

    std::ofstream output;
    output.open(outFile);
    output << code;
    output.close();
    return langCommand + outFile;
}

다음으로 출력 파일을 만들고 이전에 만든 파일을 실행하지만 stdout / stderr를 다른 출력 파일로 보냅니다.

std::string Program::run(){
    std::string command = createFile(this->lang, this->code);

    this->outputFile = createOutFileName("output.txt");

    std::stringstream newCommand;
    newCommand << command;
    newCommand << ">> ";
    newCommand << outputFile;
    newCommand << " 2>&1";

    system(newCommand.str().c_str());
    std::string output = getOutputFileData(this->outputFile);
    cleanupFiles(command);
    return output;
}

마지막으로 출력 파일에서 얻은 내용을 반환하고 이것이 코드를 실행하는 방법입니다.

더 쉬운 방법이 있다고 생각합니다. 특히 파일에 너무 많은 글을 쓰고 읽는 중이므로 어쨌든 그것을 제거 할 수 있습니까?

또한 앞으로 두 개 이상의 언어를 포함하고 싶으므로 특정 언어에 특정한 라이브러리를 사용하고 싶지 않습니다.

마지막으로, 이것이 저의 첫 번째 C ++ 프로젝트이므로 C ++ 팁을 좋아합니다!

편집 : 결국이 코드를 병렬화하고 프로그램을 캡슐화하여 실행중인 시스템을 손상시킬 수 없도록하는 방법을 찾고 싶습니다. 그것에 대해 좋은 외부 프로그램이 있으면 알려주고 stderr / stdout도 알려주십시오.

편집 : 누군가 요청했듯이 여기에 전체 저장소가 있습니다. https://github.com/lkelly93/coderunner

답변

2 MartinYork Aug 23 2020 at 00:13

system()당신 보다 popen().

차이점은 시스템이이 프로세스에 대한 액세스 권한이없는 하위 프로세스에서 명령을 실행하는 반면 popen은 하위 프로세스에서 명령을 실행 하지만 하위 프로세스 의 입력 및 출력 스트림에 대한 액세스를 제공한다는 것입니다.

이렇게하면 하위 프로세스를 실행하고 프로세스에 대한 입력을 직접 (표준 입력에 제공 한 입력 필드에서) 스트리밍 한 다음 프로세스에서 출력을 읽고 사용자 인터페이스의 출력 필드에 쓸 수 있습니다.

FILE*  proc = popen(command);
std::string inputFromUser = getUserInputFromUI();
// Using fwrite() correctly left to user.
// You need to check for errors and continue etc.
fwrite(inputFromUser.c_str(), 1, inputFromUser.size(), proc);

char  buffer[100];
std::size_t size;
while((size = fread(buffer, 1, 100, proc)) != 0) {
    // Check for read errors here.
    sendToUserInterface(std::string(bufffer, buffer + size));
}

pclose(proc);
 

관련 항목을 정렬하면 pythong 스크립트를 파일로 저장할 필요가 없습니다. python 명령 -은 이름 으로을 허용합니다. 즉, 이름이 지정된 파일이 아닌 표준 입력에서 스크립트를 읽습니다.

따라서 python 명령 (popen () 사용)을 실행 한 다음 생성 된 파일의 입력 스트림에 실행할 스크립트를 작성할 수 있습니다.

이렇게하면 중간 파일이 필요하지 않습니다.

1 aki Aug 21 2020 at 19:56

주목할만한 것들 :

  • 주석을 사용하여 만든 구현 및 섹션에 대한 문서입니다.
  • 단일 책임 원칙을 따르는 클래스, 함수 및 파일 .
  • 기능을 설명하는 이름. (아래에 언급 한 변수가 아님)
  • 테스트 프레임 워크! 그러나 테스트는 전체 프로그램뿐만 아니라 내부 기능도 확인해야합니다.

파일 스트림 및 파일 이름의 용어는 매우 혼란스럽고 조회 함수 반환 유형 또는 변수 선언을 너무 자주 만듭니다.

Program::outputFile여기서 명확하지 않은 파일 이름 입니다. 나는 그것을 FILE*.

다른 곳에서 std::ofstream output;출력은 프로그램의 출력 내용처럼 들리지만 스트림입니다!

std::string output = getOutputFileData(this->outputFile); 그리고 여기 다시 문자열입니다!


코드는 절대 및 상대 경로를 처리하지 않습니다.

테스트는 다음과 같이 실패합니다.

runnerFiles/0x1005c05c0output.txt does not exist.

이러한 코드를 사용하면 rm. 기껏해야 모든 일회용 파일을 폴더에 보관하고 사용자에게 삭제하도록 요청하십시오.


std::stringstream newCommand;
newCommand << command;
newCommand << ">> ";
newCommand << outputFile;
newCommand << " 2>&1";

system(newCommand.str().c_str());

std::stringstream피할 수 있으며 std::string첫 번째 항목이 인 한 concatenate를 직접 사용할 수 있습니다 std::string.

std::string newCommand = command + ">> " + outputFile + "2>&1";

그리고 char 버퍼 getOutputFileData를 사용 하는 코드 FILE*(할당하지 않은 것!)는 다음으로 대체 될 수 있습니다 (오류 처리 추가).

  std::ifstream run_output{outFileLocation};
  std::stringstream buffer;
  buffer << run_output.rdbuf();
  return buffer.str();
  • https://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring?noredirect=1&lq=1

선을 세밀하게 제어 할 필요가 없기 때문에 getline.

I / O에 iostreams를 선호합니다. iostream은 안전하고 유연하며 확장 가능합니다.

  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rio-streams

std::ofstream output;
output.open(outFile);
output << code;
output.close();

짧게 만들 수 있습니다.

std::ofstream output(outFile);
output << code;

필요하지 않은 경우 닫는 것을 귀찮게하지 마십시오. 때 output범위를 벗어나, 파일은 그 자체로 폐쇄 될 것입니다. 사소하게 파괴 std::vector될 수 있거나 자동으로 정리되는 배열을 모두 삭제하지 않는 것과 동일한 이유 입니다.


const &또는 std::string_view문자열이 읽기 전용 인 경우를 사용합니다 . 전달하기에 저렴하고 콘텐츠가 수정되지 않을 의도를 나타냅니다.

std::string createFile(std::string lang, std::string code)
std::string getOutputFileData(std::string outFileLocation)
bool isSupportedLanguage(std::string lang)
void Program::cleanupFiles(std::string oldCommand)

auto iter = supportedLanguages.find(lang);

C ++ 20 contains에서는 몇 줄을 절약 할 수 있습니다.

  • https://en.cppreference.com/w/cpp/container/unordered_map

this->code

대신 변수를 this->추가하거나 앞에 추가 _하여 개인 멤버임을 나타냅니다.


구현 순서가 함수 선언 순서를 따르는 경우 더 읽기 쉬운 IMO입니다.

에서는 Program, 생성자 대신에 아래의 파일의 맨 위로 이동할 수 있습니다.

  • https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nl16-use-a-conventional-class-member-declaration-order