Используя предварительно скомпилированные заголовки с CMake

Что вы видите, это последствия новой функции PowerShell v5. Format-Table теперь собирают ввод в течение 300 миллисекунд, чтобы найти лучшую ширину столбца. Он работает таким образом, даже если вы явно указали -AutoSize:$false.

Когда вы вводите команду в командной строке, эта команда неявно передается в один экземпляр команды Out-Default. Затем команда Out-Default определяет, как форматировать объекты и печатать их на хосте (консоли) PowerShell. Таким образом, даже если вы не используете Format-Table непосредственно в своем коде, это не означает, что у вас нет Format-Table в вашем конвейере. Out-Default может решить форматировать объекты как таблицу и использовать Format-Table внутренне.

Пользовательские объекты с четырьмя или менее свойствами и без специального форматирования, определенные для них в файлах формата, отформатированы как таблица. Используя Select-Object с двумя свойствами, вы создаете именно эти объекты.

Конвейер PowerShell является однопоточным. Это означает, что Format-Table не может просто выводить все собранные объекты, когда прошло интервал в 300 миллисекунд. Format-Table должны ждать, пока вы не нанесете на него следующий элемент (вызванный процесс) или конец сообщенного конвейера (вызванный конечный блок).

PS> Get-NetAdapter | Select-Object Name,Status
>>> Pause
>>> [PSCustomObject]@{Name='Some long name';Status='Some long status'} #1
>>> Pause
>>> [PSCustomObject]@{Name='Even longer name';Status='Even longer status'}
>>> Pause

Press Enter to continue...:
Name           Status
----           ------
Ethernet       Up
Some long name Some long status
Press Enter to continue...:
Even longer... Even longer s...
Press Enter to continue...:


PS>

Неявный Format-Table ничего не печатает (строго говоря он печатает пустую строку) перед первым Pause, потому что он все еще ждет больше входных объектов (еще 300 миллисекунд), чтобы определить ширину столбца. Когда первый объект (# 1) приходит через интервал 300 миллисекунд (при условии, что вы не должны нажимать клавишу Enter), тогда Format-Table выбирает ширину столбца и печатает все собранные объекты. Любые другие объекты будут напечатаны без задержки, но они больше не могут влиять на ширину столбца. Если значение является большим для столбца, оно будет усечено.

PS> Get-NetAdapter | Select-Object Name,Status | Format-Table
>>> Pause

Name     Status
----     ------
Ethernet Up


Press Enter to continue...:
PS>

С помощью этого кода до Format-Table будет выполнен конечный блок явного Format-Table. В конце блока Format-Table известно, что он уже получил все входные данные, поэтому он может выбирать ширину столбца и сразу выводить все собранные объекты. Неявные Out-Default видят, что объекты форматирования из выхода Format-Table и Out-Default знают, что им не требуется форматирование добавок и их печать на хосте (консоли) сразу же. Итак, вся таблица была напечатана до Pause.

Обратите внимание на разницу в размещении конца метки таблицы (две пустые строки). В первом примере он помещается после последнего Pause. Это потому, что неявный Format-Table все еще активен и все еще ждет, что вы передаете ему дополнительный объект. Только когда ваша команда полностью завершена Format-Table, подтвердите завершение ввода и вывода конца таблицы. Во втором примере явная Format-Table завершается до Pause, поэтому вся таблица (включая конец таблицы) печатается перед командой Pause.

Разница в размещении конца метки таблицы может быть заметил и предыдущие версии PowerShell.

98
задан Mehrdad Afshari 17 December 2008 в 07:41
поделиться

6 ответов

Даже не идите туда. Предварительно скомпилированные заголовки означают это каждый раз, когда одно из изменений заголовков, необходимо восстановить все . Вы удачливы, если у Вас есть система сборки, которая понимает это. Чаще, чем никогда, Ваша сборка просто перестанет работать, пока Вы не поймете изменение чего-то, что предварительно компилируется, и поэтому необходимо сделать, полное восстанавливает. Можно избежать этого главным образом путем предварительной компиляции заголовков, что Вы абсолютно положительны, не изменится, но тогда Вы бросаете значительную часть выигрыша в быстродействии также.

другая проблема состоит в том, что Ваше пространство имен загрязнено всеми видами символов, которые Вы не знаете или заботитесь о во многих местах, где Вы использовали бы предварительно скомпилированные заголовки.

-15
ответ дан Dirk Groeneveld 5 November 2019 в 12:19
поделиться

Вот фрагмент кода, чтобы позволить Вам использовать предварительно скомпилированный заголовок для своего проекта. Добавьте следующее к своему CMakeLists.txt, заменяющему myprecompiledheaders и myproject_SOURCE_FILES как соответствующее:

if (MSVC)

    set_source_files_properties(myprecompiledheaders.cpp
        PROPERTIES
        COMPILE_FLAGS "/Ycmyprecompiledheaders.h"
        )
    foreach( src_file ${myproject_SOURCE_FILES} )
        set_source_files_properties(
            ${src_file}
            PROPERTIES
            COMPILE_FLAGS "/Yumyprecompiledheaders.h"
            )
    endforeach( src_file ${myproject_SOURCE_FILES} )
    list(APPEND myproject_SOURCE_FILES myprecompiledheaders.cpp)
endif (MSVC)
20
ответ дан Dave Hillier 5 November 2019 в 12:19
поделиться

Что ж, когда сборки на четырехъядерном компьютере занимают более 10 минут каждый раз, когда вы меняете одну строку в любом из файлов проекта, это говорит о том, что пора добавить предварительно скомпилированные заголовки для окон. На * nux я бы просто использовал ccache и не беспокоился об этом.

Я реализовал в своем основном приложении несколько библиотек, которые оно использует. Это прекрасно работает на данный момент. Также необходимо создать исходный файл и заголовочный файл pch и включить в исходный файл все заголовки, которые вы хотите предварительно скомпилировать. Я делал это в течение 12 лет с MFC, но мне потребовалось несколько минут, чтобы вспомнить это ..

0
ответ дан 24 November 2019 в 05:04
поделиться

Я использую следующий макрос для генерации и использования предварительно скомпилированных заголовков:

MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
  IF(MSVC)
    GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
    SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch")
    SET(Sources ${${SourcesVar}})

    SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
                                PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_OUTPUTS "${PrecompiledBinary}")
    SET_SOURCE_FILES_PROPERTIES(${Sources}
                                PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_DEPENDS "${PrecompiledBinary}")  
    # Add precompiled header to SourcesVar
    LIST(APPEND ${SourcesVar} ${PrecompiledSource})
  ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)

Допустим, у вас есть переменная $ {MySources} со всеми вашими исходными файлами, код, который вы хотели бы использовать, будет просто be

ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})

Код все равно будет нормально работать и на платформах, отличных от MSVC. Довольно аккуратно :)

35
ответ дан 24 November 2019 в 05:04
поделиться

В итоге я использовал адаптированную версию макроса larsm. Использование $ (IntDir) в качестве пути к pch позволяет разделить предварительно скомпилированные заголовки для отладочных и выпускных сборок.

MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
  IF(MSVC)
    GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
    SET(PrecompiledBinary "$(IntDir)/${PrecompiledBasename}.pch")
    SET(Sources ${${SourcesVar}})

    SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
                                PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_OUTPUTS "${PrecompiledBinary}")
    SET_SOURCE_FILES_PROPERTIES(${Sources}
                                PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_DEPENDS "${PrecompiledBinary}")  
    # Add precompiled header to SourcesVar
    LIST(APPEND ${SourcesVar} ${PrecompiledSource})
  ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)

ADD_MSVC_PRECOMPILED_HEADER("stdafx.h" "stdafx.cpp" MY_SRCS)
ADD_EXECUTABLE(MyApp ${MY_SRCS})
13
ответ дан 24 November 2019 в 05:04
поделиться

Адаптировано из Дейва, но более эффективно (устанавливает целевые свойства, а не для каждого файла):

if (MSVC)
   set_target_properties(abc PROPERTIES COMPILE_FLAGS "/Yustd.h")
   set_source_files_properties(std.cpp PROPERTIES COMPILE_FLAGS "/Ycstd.h")
endif(MSVC)
13
ответ дан 24 November 2019 в 05:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: