BackEnd/C랑 C++

Boost::program_options 사용기

bell22 2022. 7. 26. 11:42

오늘은 아침부터 일이 잘 되지 않는다

머리가 잘 안 돌아가서 막막한 느낌 ㅠ.,ㅜ

그래서~~ 기분 전환 용으로 글 하나 쌈박하게 올리고 다시 열일 해보겠다

 

준호씨ㅜㅜ


이전에 작성한 boost 관련 글에도 썼다시피

나는 boost에 많은 고마움을 느낀다 +_+ 엥 이게 있다고? 하는 라이브러리가 많기 때문

이번에 시뮬레이터를 작성할 게 있어서 C로 하려다가 C++로 하려는데

세상에.. Boost에는 program options라는 기능을 제공해서

argument 기능을 참 쉽게 만들 수 있게 해 놓았다

 


1. 긴 서론

 

우리가 어떤 프로그램을 실행할 때, 옵션을 추가하여 실행을 해본 경험이 있을 것이다

argument를 프로세스 실행 파일 뒤에 추가해서 사용하곤 하는데

 

$  gcc --help
Usage: gcc [options] file...
Options:
  -pass-exit-codes         Exit with highest error code from a phase
  --help                   Display this information
  --target-help            Display target specific command line options
  --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...]
...

 

프로그램뿐만 아니라 command에 대한 정보를 얻을 때도 사용하는 방법이다

Usage를 확인하고 싶을 때 --h 또는 --help 요런 식으로 

사용할 수 있는 옵션의 목록을 확인할 수도 있다

 

이 기능을 구현할 수 있도록 라이브러리를 제공을 해주는 우리의 Boost..

 

https://www.boost.org/doc/libs/1_79_0/doc/html/program_options/tutorial.html

 

Tutorial - 1.79.0

In this section, we'll take a look at the most common usage scenarios of the program_options library, starting with the simplest one. The examples show only the interesting code parts, but the complete programs can be found in the "BOOST_ROOT/libs/program_

www.boost.org

 

시간이 조금 있을 때 한번 읽어보는 것을 추천한다

 

만약 이걸 사용하기 싫고 내가 구현하고 싶다?? 또는 C로 개발하고 싶다??

그렇다면 정말 많은 단계의 if-else 문을 쓰며 허우적거릴 것이다...

나도 그랬다

 

 


2. 사용법

 

우선 Header file 및 라이브러리는 아래와 같이 사용해야 한다

 

#include <boost/program_options.hpp>
using namespace boost::program_options;
boost_program_options

 

바로 예제부터 보고~~ 하나하나 정리해보겠다

 

 

(1) options_description

 

string name;
int age = 0;

options_description desc{"Options"};
        desc.add_options()
            ("help,h", "Help screen")
            ("name", value<string>(&name)->default_value("bell2"), "User Name")
            ("age", value<int>(&age)->notifier(on_age), "User Age");

 

options_description class를 사용하면 usage의 설명을 붙일 수 있다

또한 add_options()라는 함수에 operator()를 사용하여 편하게 항목을 추가할 수 있다

 

("name", value<string>()->default_value("bell2"), "User Name")

요렇게 쓰면 "name"은 추가할 options의 key가 되고, 두 번째 인자에는 value가 추가된다

이렇게 key, value 형태로 저장을 하면 저 key로 값을 가져오는 등의 연산이 가능하다

 

두 번째 인자의

value<string>(&name)->default_value("bell2")

요것은 --name의 옵션의 값은 string으로 가져올 것이고,

그 가져온 값을 name이라는 변수에 저장한다는 뜻이다

default_value를 설정할 수도 있고, value<string>(&name)만 사용할 수도 있다

 

그리고 세 번째 인자는 해당 옵션의 설명으로, --help 옵션을 입력 시에 커맨드 창에 보여준다

 

두 번째 인자들을 잘 보면 default_value 말고도 notifier라는 것이 있는데

value<int>(&age)->notifier(on_age)

얘는 on_age라는 callback 함수를 등록해서, age 옵션 값이 있으면 on_age()라는 함수가 call이 된다

 

 

(2) variables_map

얘가 참 재밌는 기능이라고 생각했다

 

variables_map vm;
store(parse_command_line(argc, argv, desc), vm);
notify(vm);

 

vaialbe_map이라는 건 옵션들을 key, value 형태로 map으로 저장을 해준다

 

store()

옵션들에 대해 최종 값으로 저장을 해준다

우선순위나 notify 여부 등을 포함해서~~

 

notify()

예는 옵션의 최종 값이 결정되면 해당 옵션에서 수행해야 하는 기능을 자동으로 수행해서

캡슐화할 수 있도록 해준다

아까 on_age 같은 callback 함수를 등록하면 이를 실행해준다는 뜻

 

 

(3) 결과 출력하기

 

if (vm.count("help"))
            std::cout << desc << '\n';
else if (vm.count("age"))
            std::cout << "Age: " << vm["age"].as<int>() << '\n';
else if (vm.count("name"))
            std::cout << "Name: " << vm["name"].as<string>() << '\n';
...

 

그럼 결과를 어떻게 출력하느냐

값 저장은 위해서 설명한 것처럼 value<T>(&name) 이렇게 해야 하고

만약 저장은 안 하고 가볍게 출력만 하고 싶다면

vm["age"].as<int>() 이렇게 해주면 된다

 


전체 코드는 다음과 같다

 

#include <boost/program_options.hpp>
#include <iostream>
#include <string>

using namespace boost::program_options;
using namespace std;

void on_age(int age)
{
	std::cout << "On age: " << age << '\n';
}

int main(int argc, const char *argv[])
{
	try
	{
		options_description desc{"Options"};
		desc.add_options()
			("help,h", "Help screen")
			("name", value<string>()->default_value("bell2"), "User Name")
			("age", value<int>()->notifier(on_age), "User Age");

		variables_map vm;
		store(parse_command_line(argc, argv, desc), vm);
		notify(vm);

		if (vm.count("help"))
			std::cout << desc << '\n';
		else if (vm.count("age"))
			std::cout << "Age: " << vm["age"].as<int>() << '\n';
		else if (vm.count("name"))
			std::cout << "Name: " << vm["name"].as<string>() << '\n';
	}
	catch (const error &ex)
	{
		std::cerr << ex.what() << '\n';
	}
	return 0;
}

 

그럼 이만


참고 자료

 

https://www.boost.org/doc/libs/1_79_0/doc/html/program_options/overview.html#id-1.3.32.5.7.9

 

Library Overview - 1.79.0

In the tutorial section, we saw several examples of library usage. Here we will describe the overall library design including the primary components and their function. To be a little more concrete, the options_description class is from the options descrip

www.boost.org