0
1

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.

【初心者向け】CMakeLists.txtを使ってincludeのpathを省略する。

Last updated at Posted at 2023-05-25

はじめに

この記事は前回の記事の続きになります。
前回の内容はCMakeLists.txtを使ったビルドでした。
今回はソースコードをきれいにまとめる術を書いていきたいと思います。

突然ですが、自作したヘッダーファイルをソースコードに読み込ませる時に#includeを使うと思います。
#includeを読み込む時にソースコードとヘッダーファイルの階層が違うと、ディレクトリ名を含めなければいけません。
(含めないと、どのファイルを読み込むのか、ソースコードはわかりません)

しかし、ディレクトリ名をソースコードに書くのは、少しかっちょ悪い。
なので、CMakeLists.txtに書いてしまいましょう。
というのが今回の記事になります。

参考サイト

目次

まずはビルド

ファイルの準備

今回のディレクトリ構成は以下になります。

.
├── CMakeLists.txt
├── sampleApp.cpp
└── util/
    └── file.h

sampleApp.cppの他にfile.hを用意しました。
file.hはutilフォルダに置いておきます。

今回のCMakeLists.txtの内容はこちらです。

CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(sampleApp CXX)
add_executable(sampleApp sampleApp.cpp)
target_include_directories(sampleApp PRIVATE ./util)

前回と比べて、target_include_directories()が加わりました。

sampleApp.cppとfile.hは以下になります。

sampleApp.cpp
#include <iostream>
#include "file.h"

int main(void)
{
    Write writer;
    Read reader;
    std::string file_path = "./sample_text.txt";

    writer.AddFile("Hello,World");
    writer.AddFile("Hello,World!");
    writer.AddFile("Hello,World!!");
    writer.WriteFile(file_path);

    reader.ReadFile(file_path);
    std::cout << reader.GetLine(0) << std::endl;
    std::cout << reader.GetLine(2) << std::endl;
    std::cout << reader.GetLine(1) << std::endl;
}
file.h
#pragma once

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

class Read {
public:
    int ReadFile(std::string file_path) {
        std::ifstream ifs(file_path);
        std::string str;

        if (ifs.fail()) {
            std::cerr << "Failed to open file." << std::endl;
            return -1;
        }
        while (getline(ifs, str)) {
            file_data.push_back(str);
        }
        return 0;
    }

    int LineSize() { return file_data.size(); }
    std::string GetLine(int line) { return file_data[line]; }
private:
    std::vector<std::string> file_data;
};

class Write {
public:
    void WriteFile(std::string file_path) {
        std::ofstream ofs(file_path);
        for (int i = 0; i < file_data.size(); i++) {
            ofs << file_data[i] << std::endl;
        }
    }
    void AddFile(std::string data) { return file_data.push_back(data); }
private:
    std::vector<std::string> file_data;
};

ビルド

前回と同様です。

mkdir build
cd build
cmake ..
cmake --build .

これにて、buildフォルダにsampleAppが作られます。

ファイル実行

$ ./sampleApp 
Hello,World
Hello,World!!
Hello,World!
$ ls
CMakeCache.txt  CMakeFiles  Makefile  cmake_install.cmake  sampleApp  sample_text.txt

coutの内容が出力され、sample_text.txtが生成されます。

記述内容の説明

CMakeLists.txtに記述した内容について説明していきます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(sampleApp CXX)
add_executable(sampleApp sampleApp.cpp)
target_include_directories(sampleApp PRIVATE ./util)
  • 今回、追加したのはtarget_include_directories(sampleApp PRIVATE ./util)です。
    • target_include_directories
      • 実行ファイル名、PRIVATE、リンクするフォルダを指定。
      • PRIVATE以外にPUBLIC、INTERFACEが指定できますが、今はPRIVATEだけで大丈夫です。
  • target_include_directoriesを追加したことによる効果は以下になります。
    • 本来、#includeは以下のようになる。
      sampleApp.cpp
      #include <iostream>
      #include "util/file.h"
      
    • それをフォルダ名を無くすことができます。
      sampleApp.cpp
      #include <iostream>
      #include "file.h"
      

余談

ここからは余談です。
流してしまっても構いません。

#include "util/file.h"#include "file.h"にしなければいけない理由とは何か』
かっちょ悪いから・・・、だけなわけがありません。
理由はメンテナンスの容易さです。

ヘッダーファイルが増えていき、新しくフォルダを追加するとします。
そうすると、ソースコードのフォルダパスも修正しなければいけません。

ソースコードが1ファイルのみなら修正は容易です。
しかし、数ファイルあった場合は少し手間ですよね。

その手間を省くために、この技術が役に立ちます。

『今はPRIVATEだけで大丈夫です。->他が気になる。』
簡単に説明します。
target_include_directoriesでは、実行ファイルの後にPUBLICPRIVATEINTERFACEの3つが選べます。
それぞれの説明は以下になります。

  • PUBLIC: コマンドの内容が"自分自身"と"自分に依存するターゲット"に反映される
  • PRIVATE: コマンドの内容が"自分自身"にのみ反映される
  • INTERFACE: コマンドの内容が"自分に依存するターゲット"にのみ反映される

今回、file.hは自分自身のみ使うので、PRIVATEを指定しました。
他の実行ファイルから呼ばれることになれば、PUBLICを指定したかもしれません。

『file.hの実装長くね?』
すみません。
自分が将来使いそうな実装を残しちゃいました。
C言語出身だったので、fstreamは偉大だと思い、書きました。笑

さいごに

以上で終了です。
ご参考になれば幸いです。

関連記事

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?