0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Visual Studio 2022 で UTF-8 のコンソールアプリのために CMake で参照できるライブラリを作成

Last updated at Posted at 2023-04-01

Visual Studio 2022 を使用して C++ のプロジェクトを CMake で作成する方法を紹介しています。今回は、UTF-8 のプロジェクトを作る際の手続き(コンパイルオプション・マニフェスト・コードページの切り替え)を一つにまとめてライブラリ化し、CMake の find_package() から参照できるようにする方法を報告します。プロジェクトにマニフェストファイルを用意してターゲットに追加する手間が軽減されます。

ライブラリの要件

https://qiita.com/kkoba775/items/3acfe243048266834722 でまとめたように、Visual Studio で UTF-8 を使ったプログラムを使う際には

  • コンパイルオプションに /utf-8 をつける。
  • Active Code Page を UTF8 にするための manifest ファイルをプロジェクトに追加する。
  • コンソールの出力文字コードを SetConsoleOutputCP() で変更する。

ことが有効です。これらを target_link_libraries() とヘッダファイルのインクルードだけで達成できるライブラリを作成します。

環境

  • 開発環境として、Visual Studio 2022(Community)の「C++デスクトップ環境」がインストールされていること。
  • CMake (最新版を推奨)がインストールされ、コマンドラインから cmake が実行できること。1
  • 環境変数の設定ができること。2
  • コマンドラインでの作業には「Developer Command Prompt for VS 2022」を使用すること。3

ディレクトリ構成

この記事では、ライブラリとそのソースは c:\dev にいれることにします。これは任意の場所に変更することができます。

dev/
├── utf8cp
    ├── include
    ├── lib
    ├── manifest
├── make
    ├── utf8cp
        ├── build
  • ライブラリを作るための CMakeLists.txt は c:\dev\make\utf8cp に用意します。
  • c:\dev\utf8cp にビルドしたライブラリがインストールされます。
  • インストール後、 c:\dev\make\utf8cp\build は削除できます。

ライブラリ utf8cp の作成

ディレクトリ C:\dev\make がなければ作成し、Developer Command Prompt for VS 2022 で以下を実行する。

> cd \dev\make
> md utf8cp
> cd utf8cp

c:\dev\make\utf8cp に、utf8console.hpp, utf8api.manifest, CMakeLists.txt をそれぞれ次の内容で作成する。(Visual Studio Code をインストール済みなら > code . で作業を始めると良い。)

utf8console.hpp
#pragma once
#include <windows.h>
#include <exception>

#ifndef __cpp_inline_variables
#error "C++17 is required for inline static varialbles." 
#endif

namespace automatic_utf8 {

struct chcp_utf8 {
    inline static UINT old_ = 0;
    chcp_utf8() noexcept {
        UINT cp = GetConsoleOutputCP();
        if (cp != 0 && cp != CP_UTF8) {
            old_ = cp;
            SetConsoleOutputCP(CP_UTF8);
            std::set_terminate(restore);
        }
    }

    ~chcp_utf8() noexcept {
        restore();
    }

    static void restore() noexcept {
        UINT cp = old_;
        if (cp != 0 && cp != CP_UTF8) {
            SetConsoleOutputCP(cp);
            old_ = 0;
        }
    }
};

struct automatic_chcp_utf8 {
    inline static chcp_utf8 chcp_;
};

}
  • Visual Studio はデフォルト(/Zc:__cplusplus がない場合)では __cplusplus マクロによるバージョンチェックができないので、代わりに機能テストマクロを使った。
utf8api.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
  <application>
    <windowsSettings>
      <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
    </windowsSettings>
  </application>
</assembly>
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)

project(lib_utf8cp VERSION 0.1.0 
    DESCRIPTION "Active Code Page UTF-8" LANGUAGES CXX)

add_library(utf8cp INTERFACE)

target_compile_options(utf8cp INTERFACE "/utf-8")

target_sources(utf8cp INTERFACE 
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/utf8api.manifest>
    $<INSTALL_INTERFACE:manifest/utf8api.manifest> 
)

target_include_directories(utf8cp INTERFACE 
    $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
    $<INSTALL_INTERFACE:include>
)

install(TARGETS utf8cp
    EXPORT utf8cp-config
)

install(EXPORT utf8cp-config
    NAMESPACE utf8cp::
    DESTINATION lib/cmake/utf8cp
)

install(FILES 
    ${CMAKE_SOURCE_DIR}/utf8console.hpp
    DESTINATION include
)

install(FILES
    ${CMAKE_SOURCE_DIR}/utf8api.manifest
    DESTINATION manifest
)

Developer Command Prompt for VS 2022 でライブラリのインストールを行う。

> cd \dev\make\utf8cp
> md build
> cd build
> cmake -DCMAKE_INSTALL_PREFIX="c:\dev\utf8cp" ..
> cmake --build . --target INSTALL

環境変数の設定

次のうちいずれかを行う。上にある設定が優先される。

  • 環境変数 utf8cp_DIRc:\dev\utf8cp\lib\cmake\utf8cp もしくは c:\dev を設定する。
  • 環境変数 CMAKE_PREFIX_PATHc:\dev を設定する。
  • 環境変数 Pathc:\dev\bin を追加する。

使い方

簡単な例で使い方を説明する。作業用の適当なディレクトリを用意して、以下の内容で main.cppCMakeLists.txt を作成する。main.cpp は文字コードを UTF-8 にして保存する。

main.cpp
#include <filesystem>
#include <iostream>
#include <fstream>
#include <string>

#include <utf8console.hpp>

int main() {
    std::cout << "数値以外の入力で例外が発生" << std::endl;
    std::string s;
    std::cin >> s;
    int a = std::stoi(s);

    std::filesystem::path fn = "結果";
    std::filesystem::create_directory(fn);
    fn = fn / "数値.txt";
    std::ofstream fo(fn);
    fo << "入力値 " << a << std::endl;
    std::cout << "正常終了" << std::endl;
    return 0;
} 
  • 別に utf8console.cpp を用意して、そちらで #include <utf8console.hpp> としても良い。
  • 同一ターゲットの複数のソースファイルで #include <utf8console.hpp> としても問題ない。
  • コンパイルには C++17 以上の指定が必要。
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 17)

project(test_cp CXX)

find_package(utf8cp REQUIRED)

add_executable(main main.cpp)
target_link_libraries(main utf8cp::utf8cp)

Developer Command Prompt から

> md build
> cd build
> cmake ..

とすることで Visual Studio のプロジェクトである build\main.vcxproj とソリューションである build\test_cp.sln が作成される。いずれかを Visual Studio で開くことで IDE を用いた開発ができる。あるいは IDE を使わずに、コマンドラインから

> cmake --build . --config Release
> Release\main.exe
数値以外の入力で例外が発生
775
正常終了

としてコンパイル・実行することもできる。実行を行ったディレクトリに、新しく"結果"ディレクトリが作られ、"数値.txt" に入力した数値が書き込まれる。数値以外を入力すると途中で停止するが、文字コードはもとに戻る。

> chcp
現在のコード ページ: 932

> type 結果\数値.txt
蜈・蜉帛、 775

> Release\main.exe
数値以外の入力で例外が発生
s

> chcp
現在のコード ページ: 932

参考にしたサイト

  1. https://cmake.org/ にある Latest Release の Windows x64 Installer を実行して 「Add CMake to the system PATH for all users」にチェックを入れてインストールする。

  2. 環境変数は、設定の「システム」>「バージョン情報」>「システムの詳細設定」から変更できます。> set で環境変数の一覧が見れるので、設定が反映されていない場合には一旦 Windows からサインアウトしてサインインし直してください。

  3. スタートメニューの「Visual Studio 2022」フォルダ内にショートカットがあります。「ターミナル」の設定を変更し、「既定のプロファイル」に「Developer Command Prompt for VS 2022」を登録しておくと、エクスプローラーで作業するディレクトリを開き、コンテキストメニューから「ターミナルで開く」ことができて便利です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?