Windows + Visual Studio + VSCode + CMake 的疑難雜症

Environment

  1. Windows 10
  2. Visual Studio 2019
  3. CMake 3.27.7
  4. VSCode
  5. VSCode CMake Tools

1. CMAKE_BUILD_TYPE 是空的

參考一下這篇的處理。
大致上因為 Visual Studio + CMake 並不會主動 set CMAKE_BUILD_TYPE,除非你直接呼叫 CMake 時帶上 -DCMAKE_BUILD_TYPE=Debug

cmake -DCMAKE_BUILD_TYPE=Debug path/to/source

不過都用 VSCode 了就是懶得 command line 了,只好再請出 settings.json:

{

    "cmake.configureSettings":  {
        "CMAKE_BUILD_TYPE":  "${buildType}"
    }
}

Written with StackEdit.

CMake + vcpkg + vscode

CMake + vcpkg + vscode

  1. CMake 3.27.7
  2. CMake Tools
  3. VSCode

安裝的部份就跳過了,使用 Windows 和 boost::filesystem 當例子。

Key takeaways

vcpkg

使用 manifest mode,不開 vcpkg global integration。在 workspace root 下產生 vcpkg.json

{
    "$schema":  "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
    "name":  "test",
    "version":  "0.1.0",
    "dependencies":  [
        "boost-filesystem"
    ]
}

CMake

修改 .vscode/settings.json 讓 CMake 可以使用 vcpkg。

{
    "cmake.configureSettings": {
        "CMAKE_TOOLCHAIN_FILE": "you-path-to-vcpk/scripts/buildsystems/vcpkg.cmake",
        "VCPKG_TARGET_TRIPLET": "x64-windows"
    }
}

CMake

find_package(Boost REQUIRED COMPONENTS filesystem)

if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(hello PRIVATE ${Boost_LIBRARIES})
else()
    message(FATAL_ERROR "Boost not found. Please install Boost.")
endif()

Troubleshooting

Boost Not Found

  1. 先清掉 CMake cache 試試看:如果過程中,已經反覆 CMake -G 過,可能受到 CMake cache 影響,導致 find_package(Boost, ...) 不會再重頭開始找。

  2. 修改 .vscode/settings.json已開啟 CMake find boost debug log,方法如下:

    {
        "cmake.configureSettings": {
            ...
            "Boost_DEBUG": "on"
        }
    }
    
  3. 放棄 vscode ,繞過 CMake tool extension 的部份。

Reference

  1. vcpkg in CMake projects

Written with StackEdit.

CMake + vcpkg + vscode

CMake + vcpkg + vscode

  1. CMake 3.27.7
  2. CMake Tools
  3. VSCode

安裝的部份就跳過了,使用 Windows 和 boost::filesystem 當例子。

Key takeaways

vcpkg

使用 manifest mode,不開 vcpkg global integration。在 workspace root 下產生 vcpkg.json

{
    "$schema":  "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
    "name":  "test",
    "version":  "0.1.0",
    "dependencies":  [
        "boost-filesystem"
    ]
}

CMake

修改 .vscode/settings.json 讓 CMake 可以使用 vcpkg。

{
    "cmake.configureSettings": {
        "CMAKE_TOOLCHAIN_FILE": "you-path-to-vcpk/scripts/buildsystems/vcpkg.cmake",
        "VCPKG_TARGET_TRIPLET": "x64-windows"
    }
}

CMake

find_package(Boost REQUIRED COMPONENTS filesystem)

if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(hello PRIVATE ${Boost_LIBRARIES})
else()
    message(FATAL_ERROR "Boost not found. Please install Boost.")
endif()

Troubleshooting

Boost Not Found

  1. 先清掉 CMake cache 試試看:如果過程中,已經反覆 CMake -G 過,可能受到 CMake cache 影響,導致 find_package(Boost, ...) 不會再重頭開始找。

  2. 修改 .vscode/settings.json已開啟 CMake find boost debug log,方法如下:

    {
        "cmake.configureSettings": {
            ...
            "Boost_DEBUG": "on"
        }
    }
    
  3. 放棄 vscode ,繞過 CMake tool extension 的部份。

Reference

  1. vcpkg in CMake projects

Written with StackEdit.

StackEdit 測試

這是標題

This is a source code - of course - a C++ hello world.

#include <iostream>

int main( int argc, char* argv[] )
{
    std::cout << "Hello World" << std::endl;
    return 0;
}

看起來還不錯,真希望有 native editor 版本 …

Written with StackEdit.

auto + braced-init-list 在 direct initialization 和 copy initialization 中的差異

C++17 中有條修改 n3922 細想之後挺有意思的。 C++11 中規定,下面的程式碼會推導出一個 std::initializer_list<int>:
auto i{ 10 }; // i is a std::initializer_list<int>
當初在 C++11 看到時,覺得的確不太直覺,但當時記性還行,索性就記得說:新語言特性(auto)喜歡跟新語言特性(initializer_list)一起。後來在 C++17 中修改了,
For direct list-initialization:

1. For a braced-init-list with only a single element, auto deduction will deduce from that entry;
2. For a braced-init-list with more than one element, auto deduction will be ill-formed.
也就是說,C++17 後變成了: auto + direct initialization + braced-init-list 只能初始化單一一個變數。
auto i{ 10 }; // legal and i is a std::initialize_list<int>
auto i{ 10, 11 }; // illegal
岔題一下:auto + direct initialization + braced-init-list 沒辦法用在 C-style array 上,所以下面在 C++11 和 C++17 都是非法的。
auto array[]{ 10, 11 }; // illegal
auto array2[ 2 ]{ 10, 11 }; // illegal
但如果今天場景變成 auto + copy initialization + braced-init-list 那就總是會定義出一個 std::initialize_list<int> 變數了。
auto i = { 10 }; // legal and i is a std::initializer_list<int>
auto array = { 10, 11 }; // legal and array is a std::initializer_list<int>
哎,那這次要怎麼記得這件規則呢?顧名思義:等號右邊是 braced-init-list ,所以它原本就是 std::initialize_list<int> ,那既然是 copy initialization 。那就連型別也一起 copy 吧~真是太哲學了! 好吧,因為是哲學,所以有點不太科學:return value 可以視為一種 copy initialization ,但這情況下,是不能使用 auto 推導出 std::initialize_list<int> 的,因為 braced-init-list 不是一個 expression ,並不會產生一個 value [1] 。因此 return type 需要一個明確的型別來搭配,並用來呼叫 return type 的 constructor 的 ...
auto f()
{
    return {1,2}; // ill-formed, {1,2} is not an expression
}
...

Use bu in WinDbg and get `Couldn't resolve error at module!func`

在 WinDbg 中設定 breakpoint 時如果遇到 symbol mismatching ,那 WinDbg 就會提示 Couldn't resolve error at module!func 。不過有趣的是,如果今天是用 bu module!func 也遇到一樣的問題,那還會是 symbol not found 嗎?如果此時 stack 是停在 nt!DebugService2 時,那就很有可能也是 symbol not found 了。
0: kd> bu module!func

0: kd> g
Breakpoint 0's offset expression evaluation failed.
Check for invalid symbols or bad syntax.
WaitForEvent failed
nt!DebugService2+0x6:
fffff806`31805296 c3              ret

1: kd> k
 # Child-SP          RetAddr           Call Site
00 ffffde00`16226b68 fffff806`31771955 nt!DebugService2+0x6
01 ffffde00`16226b70 fffff806`317718e7 nt!DbgLoadImageSymbols+0x45
02 ffffde00`16226bc0 fffff806`31b558f1 nt!DbgLoadImageSymbolsUnicode+0x33
03 ffffde00`16226c00 fffff806`31b55423 nt!MiDriverLoadSucceeded+0x18d
04 ffffde00`16226ca0 fffff806`31b54c06 nt!MmLoadSystemImageEx+0x807
05 ffffde00`16226e40 fffff806`31b3800c nt!MmLoadSystemImage+0x26
06 ffffde00`16226e80 fffff806`31b36f22 nt!IopLoadDriver+0x23c
07 ffffde00`16227050 fffff806`31b36c32 nt!PipCallDriverAddDeviceQueryRoutine+0x1be
08 ffffde00`162270e0 fffff806`31b365f0 nt!PnpCallDriverQueryServiceHelper+0xda
09 ffffde00`16227190 fffff806`31b35d83 nt!PipCallDriverAddDevice+0x41c
0a ffffde00`16227350 fffff806`31b2fcc6 nt!PipProcessDevNodeTree+0x333
0b ffffde00`16227420 fffff806`3176efba nt!PiRestartDevice+0xba
0c ffffde00`16227470 fffff806`3168e5c5 nt!PnpDeviceActionWorker+0x46a
0d ffffde00`16227530 fffff806`317265f5 nt!ExpWorkerThread+0x105
0e ffffde00`162275d0 fffff806`318048d8 nt!PspSystemThreadStartup+0x55
0f ffffde00`16227620 00000000`00000000 nt!KiStartSystemThread+0x28

1: kd> bc *

1: kd> bu module!func
Couldn't resolve error at 'vmodule!func'

為什麼呢?此時不是使用 Set Unresolved Breakpoint 嗎?嗯嗯,Unresolved Breakpoint 也是有需要 resolve 的時候,剛好系統正在載入新 module ,而且符合 bu 指定的 module name ,那就會開始 resolve symbol name ,如果找不到一樣會跳出 Couldn't resolve error at 'vmodule!func' 了。

boost.test BOOST_CHECK_EXCEPTION 竟然不支援 lambda

如題 BOOST_CHECK_EXCEPTION 竟然不支援用 lambda 寫 predicator ...
	
    BOOST_CHECK_EXCEPTION(
        p.parseString("---\n---"),
        durin::yaml::ParserException, 
        []( const durin::yaml::ParserException& ex ) {
        	return ex.what() == std::string( "Double DocBegin" );
        });
	
Feel so sad ...

KDE Craft 初試

雖然越來越多的 web-based UML editor 可以用,而且感覺 portability 也不錯,不像 native editor 可能還會被綁死在特定 file format 上,不過怎麼說呢?細節上的操作性還是有差,以前工作 Windows only ,用還是 open source 版本的 StarUML 也是挺愜意的,但隨著 MacOS, Linux 近來攪和後,就屬意了 Umbrello ,只是好像有時候不是很穩定,想來自己貢獻一下,沒想到 KDE 貌似就有兩套 build tool,craft 和 kdesrc-build ,太折騰了… craft 用 python 寫的,比起 kdesrc-build 用 perl ,那還是玩玩看 craft 吧,沒想到還是要用到 python27 Orz ...

Native Blog Editor

唉唉,2021都要結束了,找個 blog friendly 的 native editor 還是很困難,應該說從來沒簡單過,加上又是一個時代的結束…

Windows + Visual Studio + VSCode + CMake 的疑難雜症

Environment Windows 10 Visual Studio 2019 CMake 3.27.7 VSCode VSCode CMake Tools 1. CMAKE_BUILD_TYPE 是空的 參考一下 這篇 的處理。 大致上因為 Visual...