Cmake

Este documento fornece uma rápida visão geral do CMake – uma alternativa de plataforma cruzada aos linux Makefiles e make. Para ajuda no uso de make e Makefiles sem CMake, por favor veja a documentação do Prof. Newhall. Este documento foi escrito para a versão 2.6 do cmake, que está instalado nas máquinas de laboratório via stow (a partir de janeiro de 2009).

Porquê CMake

Eu pessoalmente gosto de CMake porque parece mais intuitivo do que escrever um Makefile padrão. Coisas básicas e comuns são bem fáceis e coisas mais difíceis são possíveis, embora a maioria das coisas que eu construo seja bem básica. Para demonstrar o CMake, incluí alguns exemplos de código no arquivo cmake.tgz (4 KB). Salve o arquivo e descompacte o conteúdo em qualquer lugar do seu diretório. Por exemplo:

$ tar xzvf cmake.tgz$ cd cmake$ lsCMakeLists.txt w01-cpp/
CMakeLists.txt

CMake é controlado por instruções de escrita nos arquivos CMakeLists.txt. Cada diretório em seu projeto deve ter um arquivo CMakeLists.txt. O que é bom no CMake é que os arquivos CMakeLists.txt em um subdiretório herdam propriedades definidas no diretório pai, reduzindo a quantidade de duplicação de código. Para nosso projeto de exemplo, temos apenas um subdiretório: w01-cpp. O arquivo CMakeLists.txt para o diretório cmake de nível superior é bastante simples, mas demonstra algumas características chave.

cmake_minimum_required(VERSION 2.6)project(CMAKEDEMO)#There are lots of scripts with cmake#for finding external libraries. #see /usr/local/share/cmake-2.6/Modules/Find*.cmake for more examplesfind_package(GLUT)find_package(OpenGL)set(CMAKE_CXX_FLAGS "-g -Wall")add_subdirectory(w01-cpp)

Este código demo inclui código que requer bibliotecas OpenGL externas para gráficos. Em uma configuração Makefile típica nós provavelmente precisaríamos especificar onde os arquivos de cabeçalho OpenGL estão, por exemplo, -I/usr/local/include, quais bibliotecas usar, por exemplo, -lGL -lGLU -lglut, e a localização das bibliotecas. A localização dos arquivos de cabeçalho e das bibliotecas provavelmente varia de instalação para instalação e de plataforma para plataforma. No entanto, geralmente há alguns lugares padrão para procurar, e o CMake automatiza essa busca usando as macros find_package. Assim, find_package(GLUT) e find_package(OpenGL) encontra a localização dos arquivos de cabeçalho e das bibliotecas e configura as bibliotecas mais comuns que estão ligadas em um projeto OpenGL típico. O CMake tem suporte para encontrar muitos pacotes. Veja /usr/local/share/cmake-2.6/Modules/Find*.cmake para mais exemplos. Para usar um desses scripts, use find_package(PKGname) se o script CMake se chamar FindPKGname.cmake.

Para mais informações sobre como encontrar bibliotecas externas ou criar suas próprias macros de pacotes find, veja o wiki KitWare no assunto.

Você pode definir flags comuns que você definiria em um típico conjunto de usuários Makefile(VARNAME VALUE). Neste exemplo eu activei os símbolos de depuração (-g) e todos os avisos (-Wall). Eu também dei um nome a este projeto CMake usando o project(CMAKEDEMO). Você pode dar o nome que quiser ao seu projeto. Vamos usar esta informação no ficheiro CMakeLists.txt no directório w01-cpp. Finalmente indicamos que a maioria do código está realmente no arquivo w01-cpp dizendo ao nosso arquivo CMakeLists.txt de nível superior para add_subdirectory(w01-cpp)

Vamos dar uma olhada no arquivo CMakeLists.txt no subdiretório w01-cpp:

include_directories(${CMAKEDEMO_SOURCE_DIR}/w01-cpp)link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp)#the one C fileadd_executable(cdemo cdemo.c)target_link_libraries(cdemo m) #link the math library#these are all compiled the same wayset(PROGRAMS oglfirst pointers)set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m)foreach(program ${PROGRAMS}) add_executable(${program} ${program}.cpp) target_link_libraries(${program} ${CORELIBS})endforeach(program)#building just a library. add_library(geometry geometry.cpp)add_executable(test_geometry test_geometry.cpp)#linking against a custom librarytarget_link_libraries(test_geometry ${CORELIBS} geometry)

A macro include_directories diz ao CMake onde procurar por arquivos fonte. Ao declarar o nome do projeto CMAKEDEMO no arquivo CMakeLists.txt de nível superior, as variáveis CMAKEDEMO_SOURCE_DIR e CMAKEDEMO_BINARY_DIR são definidas dependendo da localização atual do seu código e da localização atual do seu diretório de compilação (mais sobre esta última localização mais tarde). Adicionar um alvo para um novo executável binário é fácil. Basta adicionar uma linha add_executable(cdemo cdemo.c). O CMake irá automaticamente descobrir o compilador baseado na extensão do tipo de arquivo. Se bibliotecas adicionais forem necessárias, você pode dizer ao CMake para fazer um link contra elas usando target_link_libraries(cdemo m). Isto diz ao CMake que o programa cdemo precisa se conectar contra a biblioteca matemática. Você pode fazer um link contra mais de uma biblioteca especificando as bibliotecas em uma lista. Veja por exemplo set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m). As variáveis GLUT_LIBRARY e OPENGL_LIBRARY são definidas pelo CMake quando usamos o find_package(GLUT) e find_package(OpenGL). Para descobrir quais variáveis são definidas ao usar o find_package, você provavelmente precisará abrir o arquivo Find*.cmake apropriado e ler a documentação geralmente útil, mas tersa.

Desde que vários programas nesta pasta w01-cpp são compilados da mesma forma e ligados contra as mesmas bibliotecas, podemos processá-los todos com um simples loop mostrado acima usando a macro foreach no CMake. Finalmente mostramos como criar nossa própria biblioteca usando add_library(geometry geometry.cpp) e ligando contra esta biblioteca em target_link_libraries(test_geometry ${CORELIBS} geometry).

Construindo com CMake

Configurar um monte de arquivos CMakeLists.txt não permitirá que você construa seu projeto imediatamente. CMake é apenas um invólucro de plataforma cruzada em torno dos sistemas de construção mais tradicionais. No caso do linux, isto significa fazer. Um rápido passo de pré-processamento irá converter sua descrição CMakeLists.txt em um sistema tradicional de compilação make automaticamente. Uma característica agradável e altamente recomendada do CMake é a capacidade de fazer builds fora do código fonte. Desta forma você pode fazer todos os seus arquivos .o, vários arquivos temporários dependentes, e até mesmo os executáveis binários sem desordenar a sua árvore de código fonte. Para usar builds fora do código-fonte, crie um diretório de build na sua pasta de nível superior (tecnicamente, isto pode estar em qualquer lugar, mas a pasta de projeto de nível superior parece ser uma escolha lógica). Em seguida, mude para o seu diretório de compilação e execute cmake apontando-o para o diretório do CMakeLists.txt de nível superior. Por exemplo:

cumin$ cd cmake/cumin$ lsCMakeLists.txt w01-cpp/cumin$ mkdir buildcumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ cd build/cumin$ cmake ..

Remember to be in your build directory and point cmake only to the directory containing the top-level CMakeLists.txt file, not the file itself. Se tudo correr bem, cmake irá processar seus arquivos CMakeLists.txt, encontrar a localização de todas as bibliotecas e incluir caminhos e enviar um monte de informações de configuração, incluindo um Makefile tradicional em seu diretório de compilação. (Se você tem alguma familiaridade com autotools/autohell, este processo de cmake é similar ao ./configure). Agora você está pronto para compilar usando o sistema make tradicional. Execute o make no seu diretório de compilação para compilar e vincular tudo. CMake até mesmo joga em algumas cores legais, barras de progresso, e suprime um monte de saída do gcc. Se você quiser uma saída verbosa, você pode digitar VERBOSE=1 make (útil se algo der errado).

Por causa da forma como configuramos o build fora do código fonte e os diretórios link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp), nossos binários recém compilados estão na pasta w01-cpp no diretório de build onde acabamos de rodar o make.

cumin$ cd w01-cpp/cumin$ lsCMakeFiles/ cdemo* libgeometry.a pointers*Makefile cmake_install.cmake oglfirst* test_geometry*cumin$ ./cdemo Sqrt(2) = 1.4142 This concludes a short C democumin$ ./oglfirst cumin$ ./test_geometry 

Pressione ESC para sair da demo OpenGL.

Wrapping up

Se você modificar o código no seu diretório fonte, incluindo até mesmo um arquivo CMakeLists.txt e executar novamente o make no diretório de compilação, make e cmake irá recompilar e reconstruir as alterações necessárias. Se você só está fazendo alterações em um subdiretório, você pode simplesmente executar make no subdiretório correspondente na árvore de compilação para processar atualizações.

Uma fonte inicial de confusão com builds fora do código fonte é que você basicamente tem duas cópias da sua árvore de código fonte, uma com código fonte real, e outra com Makefiles e executáveis binários (na árvore de compilação). É provavelmente melhor manter duas janelas abertas com uma na árvore de compilação para fazer e rodar seus programas, e uma janela na árvore de código fonte para modificar os arquivos fonte.

Uma coisa legal sobre compilações fora do código fonte é que limpar arquivos objetos, arquivos makedepend, binários, e outros miscelâneos do build cruft pode ser feito simplesmente apagando todo o diretório de compilação porque não há código fonte. Você também pode usar make clean para limpar os arquivos objetos e binários reais, mas quando você está planejando tar up seu código fonte ou distribuir seu código para as massas, você pode simplesmente fazer

cumin$ cd cmakecumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ rm -rf build/cumin$ lsCMakeLists.txt w01-cpp/

para limpar e empacotar seu código.

Mais para explorar

Isso só toca a superfície do que o CMake pode fazer. Confira o CMake Wiki para mais informações. Espero atualizar esta página se encontrarmos exemplos mais complexos, e fico feliz em receber feedback ou dicas de outros cursos que possam estar usando o CMake. Para usuários muito avançados, o CMake tem um programa companheiro CPack para empacotar automaticamente binários e fontes para sistemas Ubuntu/Debian (.deb), Red Hat (.rpm), OSXX11, tgz, CygWin, e Nullsoft.

Deixe uma resposta

O seu endereço de email não será publicado.