Usando o Docker para criar e executar um projeto C ++

Esta postagem falará sobre como criar um projeto C ++ usando o GTest e o Boost usando o Docker. O artigo é uma receita com alguns comentários explicativos; a solução apresentada no artigo não pretende estar pronta para a produção.


Por que e quem pode precisar?


Suponha que você, como eu, realmente goste do conceito de Python venv , quando todas as dependências necessárias estiverem localizadas em um diretório separado e estritamente definido; ou você precisa fornecer portabilidade simples do ambiente de montagem e teste para o projeto em desenvolvimento, o que é muito conveniente, por exemplo, ao ingressar um novo desenvolvedor na equipe.


Este artigo será especialmente útil para desenvolvedores iniciantes que precisam executar configurações básicas do ambiente para criar e executar um projeto C ++.


O ambiente apresentado no artigo pode ser usado como uma estrutura para tarefas de teste ou trabalho de laboratório.


Instalar o Docker


Tudo o que você precisa para implementar o projeto apresentado neste artigo é Docker e acesso à Internet.


O Docker está disponível para plataformas Windows, Linux e Mac. A documentação oficial .


Desde que eu uso uma máquina Windows a bordo, eu apenas tive que baixar o instalador e executá-lo.


Observe que, no momento, o Docker para Windows usa o Hyper-V para o seu trabalho.


Projeto


Como projeto, queremos dizer um aplicativo CommandLine que exibe a string "Hello World!" para o fluxo de saída padrão.


O projeto usará as bibliotecas mínimas necessárias, bem como o CMake como um sistema de construção.


A estrutura do nosso projeto será a seguinte:


project | Dockerfile | \---src CMakeLists.txt main.cpp sample_hello_world.h test.cpp 

O arquivo CMakeLists.txt contém uma descrição do projeto.
Código fonte do arquivo:


 cmake_minimum_required(VERSION 3.2) project(HelloWorldProject) #  C++17 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") #  Boost.Program_options #   ,     set(Boost_USE_STATIC_LIBS ON) find_package(Boost COMPONENTS program_options REQUIRED) include_directories(${BOOST_INCLUDE_DIRS}) #     add_executable(hello_world_app main.cpp sample_hello_world.h) target_link_libraries(hello_world_app ${Boost_LIBRARIES}) #  CTest enable_testing() #       GoogleTest find_package(GTest REQUIRED) include_directories(${GTEST_INCLUDE_DIRS}) #    add_executable(hello_world_test test.cpp sample_hello_world.h) target_link_libraries(hello_world_test ${GTEST_LIBRARIES} pthread) #       CTest add_test(NAME HelloWorldTest COMMAND hello_world_test) 

O arquivo sample_hello_world.h contém uma descrição da classe HelloWorld, enviando uma instância para o fluxo, a sequência "Hello World!" Será exibida. Essa complexidade se deve à necessidade de testar o código do nosso aplicativo.
Código fonte do arquivo:


 #ifndef SAMPLE_HELLO_WORLD_H #define SAMPLE_HELLO_WORLD_H namespace sample { struct HelloWorld { template<class OS> friend OS& operator<<(OS& os, const HelloWorld&) { os << "Hello World!"; return os; } }; } // sample #endif // SAMPLE_HELLO_WORLD_H 

O arquivo main.cpp contém o ponto de entrada do nosso aplicativo, também adicionaremos Boost.Program_options para simular um projeto real.


Código fonte do arquivo:


 #include "sample_hello_world.h" #include <boost/program_options.hpp> #include <iostream> //         - "--help" auto parseArgs(int argc, char* argv[]) { namespace po = boost::program_options; po::options_description desc("Allowed options"); desc.add_options() ("help,h", "Produce this message"); auto parsed = po::command_line_parser(argc, argv) .options(desc) .allow_unregistered() .run(); po::variables_map vm; po::store(parsed, vm); po::notify(vm); //  C++17     std::make_pair return std::pair(vm, desc); } int main(int argc, char* argv[]) try { auto [vm, desc] = parseArgs(argc, argv); if (vm.count("help")) { std::cout << desc << std::endl; return 0; } std::cout << sample::HelloWorld{} << std::endl; return 0; } catch (std::exception& e) { std::cerr << "Unhandled exception: " << e.what() << std::endl; return -1; } 

O arquivo test.cpp contém o mínimo necessário - um teste da funcionalidade da classe HelloWorld. Para testar, usamos o GoogleTest .
Código fonte do arquivo:


 #include "sample_hello_world.h" #include <sstream> #include <gtest/gtest.h> //  ,  HelloWorld  ,     TEST(HelloWorld, Test) { std::ostringstream oss; oss << sample::HelloWorld{}; ASSERT_EQ("Hello World!", oss.str()); } //      int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } 

Em seguida, vamos para a parte mais interessante - configurando seu ambiente de construção usando o Dockerfile!


Dockerfile


Para montagem, usaremos o gcc da versão mais recente.
O Dockerfile contém dois estágios: construindo e iniciando nosso aplicativo.
Para executar, use a versão mais recente do Ubuntu.


Conteúdo do Dockerfile:


 #  --------------------------------------- #        gcc:latest FROM gcc:latest as build #      GoogleTest WORKDIR /gtest_build #        GoogleTest #     ,  # Docker   RUN   , #   ,   ,   RUN apt-get update && \ apt-get install -y \ libboost-dev libboost-program-options-dev \ libgtest-dev \ cmake \ && \ cmake -DCMAKE_BUILD_TYPE=Release /usr/src/gtest && \ cmake --build . && \ mv lib*.a /usr/lib #   /src   ADD ./src /app/src #       WORKDIR /app/build #    ,     RUN cmake ../src && \ cmake --build . && \ CTEST_OUTPUT_ON_FAILURE=TRUE cmake --build . --target test #  --------------------------------------- #      ubuntu:latest FROM ubuntu:latest #  ,    Docker    root #     root'  :) RUN groupadd -r sample && useradd -r -g sample sample USER sample #      WORKDIR /app #         COPY --from=build /app/build/hello_world_app . #    ENTRYPOINT ["./hello_world_app"] 

Acho que, por enquanto, continue criando e executando o aplicativo!


Montagem e lançamento


Para criar nosso aplicativo e criar uma imagem do Docker, basta executar o seguinte comando:


 #  docker-cpp-sample    # . -    ,  Dockerfile docker build -t docker-cpp-sample . 

Para iniciar o aplicativo, use o comando:


 > docker run docker-cpp-sample 

Veremos as palavras queridas:


 Hello World! 

Para passar um parâmetro, basta adicioná-lo ao comando acima:


 > docker run docker-cpp-sample --help Allowed options: -h [ --help ] Produce this message 

Resumir


Como resultado, criamos um aplicativo C ++ completo, configuramos o ambiente para compilar e executá-lo no Linux e o envolvemos em um contêiner Docker. Assim, liberando os desenvolvedores subseqüentes da necessidade de gastar tempo configurando uma montagem local.

Source: https://habr.com/ru/post/pt414109/


All Articles