| 20 | constexpr TStringBuf modPrefix = "mod="; |
| 21 | |
| 22 | int main(int argc, char** argv) { |
| 23 | if ((argc - 1) % 3 != 0) { |
| 24 | Cerr << "Usage:\n\t" << argv[0] << " (mod=SRC_PATH_X SRC OUT)+" << Endl; |
| 25 | return 1; |
| 26 | } |
| 27 | |
| 28 | PyConfig cfg{}; |
| 29 | PyConfig_InitIsolatedConfig(&cfg); |
| 30 | cfg._install_importlib = 0; |
| 31 | Y_SCOPE_EXIT(&cfg) {PyConfig_Clear(&cfg);}; |
| 32 | |
| 33 | for (int i = 0; i < (argc - 1)/3; ++i) { |
| 34 | const TString srcpath{TStringBuf{argv[3*i + 1]}.substr(modPrefix.size())}; |
| 35 | const TFsPath inPath{argv[3*i + 2]}; |
| 36 | const char* outPath = argv[3*i + 3]; |
| 37 | |
| 38 | const auto status = Py_InitializeFromConfig(&cfg); |
| 39 | if (PyStatus_Exception(status)) { |
| 40 | Py_ExitStatusException(status); |
| 41 | } |
| 42 | Y_SCOPE_EXIT() {Py_Finalize();}; |
| 43 | |
| 44 | TPyObject bytecode{Py_CompileString( |
| 45 | TFileInput{inPath}.ReadAll().c_str(), |
| 46 | srcpath.c_str(), |
| 47 | Py_file_input |
| 48 | )}; |
| 49 | if (!bytecode) { |
| 50 | Cerr << "Failed to compile " << outPath << Endl; |
| 51 | PyErr_Print(); |
| 52 | return 1; |
| 53 | } |
| 54 | |
| 55 | if (FILE* out = fopen(outPath, "wb")) { |
| 56 | PyMarshal_WriteObjectToFile(bytecode.Get(), out, Py_MARSHAL_VERSION); |
| 57 | fclose(out); |
| 58 | if (PyErr_Occurred()) { |
| 59 | Cerr << "Failed to marshal " << outPath << Endl; |
| 60 | PyErr_Print(); |
| 61 | return 1; |
| 62 | } |
| 63 | } else { |
| 64 | Cerr << "Failed to write " << outPath << ": " << std::error_code{errno, std::system_category()}.message() << Endl; |
| 65 | return 1; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | return 0; |
| 70 | } |