Экспорт сообщений об ошибках компиляции g++ из библиотеки TMB в текстовый файл

Я пытаюсь скомпилировать модель с gcc (C++) в R (используя пакет TMB). Ошибки настолько многочисленны, что в Rstudio я даже не могу прокрутить вверх, чтобы увидеть их начало. Поэтому я хотел бы распечатать все в консоли (сообщения, ошибки и предупреждения) в текстовый файл. Таким образом, я мог бы также сравнить различные результаты модели (или, в частности, их ошибки).

Я пробовал следующие вещи:

fileConn<-file("Fail.txt")
writeLines(compile("Mymodel.cpp"), fileConn) 
close(fileConn)

=> Дает мне пустой файл (который я более или менее ожидал)

zz <- file("Fail.txt", open = "wt")
sink(zz, type = "message")
compile("Mymodel.cpp")
sink()

=> печатает только последнюю ошибку

Что я упустил?

2 ответа

Решение

Вы не предоставили свой compile() функция, но я предполагаю, что она запускает системную команду, которая вызывает g++ Скомпилировать Mymodel.cpp,

В этом случае g++ процесс выведет свой вывод ошибок в stderr. Единственный способ захватить этот вывод, используя R, это вызвать system2() с stderr=T, Обратите внимание, что system() не может напрямую захватывать stderr (хотя он может захватывать stdout через intern=T и вы могли бы добавить 2>&1 в команду оболочки для захвата stderr вместе с ним, так что это еще один жизнеспособный вариант). sink() не захватывает вывод системных команд; он только захватывает вывод R

Я рекомендую передать аргументы compile() функция к system2() вызов, таким образом, параметризация ли ваш вызов compile() результаты в g++ sderder собирается в терминал или на возвращаемое значение вашего compile() функция. Вот как это будет сделано:

write('error!','test1.cpp'); ## generate a test file with invalid C++
compile <- function(file,...) system2('g++',file,...);
compile('test1.cpp'); ## output lost to the terminal
## test1.cpp:1:1: error: ‘error’ does not name a type
##  error!
##  ^
output <- compile('test1.cpp',stdout=T,stderr=T); ## capture output
## Warning message:
## running command ''g++' 'test1.cpp' 2>&1' had status 1
output;
## [1] "test1.cpp:1:1: error: ‘error’ does not name a type"
## [2] " error!"
## [3] " ^"
## attr(,"status")
## [1] 1
write(output,'output.txt'); ## write output to a text file
cat(readLines('output.txt'),sep='\n'); ## show it
## test1.cpp:1:1: error: ‘error’ does not name a type
##  error!
##  ^

Если вы действительно хотите захватить весь вывод, сгенерированный в вашем compile() функции, то вы можете объединить вышеуказанное решение с sink() как показано здесь: Как сохранить весь вывод консоли в файл в R?,

В этом случае я бы порекомендовал отказаться от идеи аргументов с переменным аргументом и добавить один дополнительный аргумент в compile(), который будет принимать имя выходного файла, в который будут записаны все выходные данные.

Это потребует нескольких предположений об отсутствии дополнительного аргумента:

write('error!','test1.cpp'); ## generate a test file with invalid C++
compile <- function(file,outputFile) {
    if (!missing(outputFile)) {
        outputCon <- file(outputFile,'wt'); ## require file name
        sink(outputCon);
        sink(outputCon,type='message'); ## must sink messages separately
        warn.old <- options(warn=1)$warn; ## necessary to capture warnings as they occur
    }; ## end if
    cat('some random output 1\n');
    if (!missing(outputFile)) {
        output <- system2('g++',file,stdout=T,stderr=T); ## before flush to get warnings
        sink(); ## force flush before appending system command output
        sink(type='message');
        outputCon <- file(outputFile,'at'); ## must reopen connection for appending
        write(output,outputCon);
        sink(outputCon);
        sink(outputCon,type='message');
    } else {
        system2('g++',file);
    }; ## end if
    cat('some random output 2\n');
    if (!missing(outputFile)) {
        sink();
        sink(type='message');
        options(warn=warn.old);
    }; ## end if
}; ## end compile()
compile('test1.cpp'); ## output lost to the terminal
## some random output 1
## test1.cpp:1:1: error: ‘error’ does not name a type
##  error!
##  ^
## some random output 2
compile('test1.cpp','output.txt'); ## internally capture all output
cat(readLines('output.txt'),sep='\n'); ## show it
## some random output 1
## Warning: running command ''g++' test1.cpp 2>&1' had status 1
## test1.cpp:1:1: error: ‘error’ does not name a type
##  error!
##  ^
## some random output 2

Это старый вопрос, но я нашел простое решение, чтобы получить вывод файла журнала для TMB::compile, которого я больше нигде не нашел.
Как указано выше, sink() не фиксирует вывод системных команд; он только захватывает вывод R Однако любой аргумент, не указанный в функции compile из библиотеки TMB передаются как переменные Makeconf. Таким образом, вам нужно только передать классическую команду вывода с путем к целевому лог-файлу в строковом формате:

TMB::compile(file = "Mymodel.cpp", "&> /tmp/logfile.log")
Другие вопросы по тегам