Я пытаюсь скомпилировать модель с 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()
=> печатает только последнюю ошибку
Что я упустил?
Вы не предоставили свой 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")