Prévia do material em texto
Cmake
Conforme eu tinha comentado em um post anterior, minha tarefa dessa semana era
desenvolver um shader para interfacear com o OSL. A primeira etapa dessa tarefa é
permitir a chamada de funções do OSL. Apanhei bastante para fazer isso.
Recentemente o BRL-CAD migrou seu sistema de construção do autotools para
o cmake. O pouco que sei sobre cmake, é que ele é um sistema multi-plataforma
para compilar um projeto. Você descreve, em um nível mais alto,
os CMakeLists.txt em cada diretório do seu projeto. No caso mais básico, executa o
comando cmake no diretório raíz e serão gerados os Makefile‘s. Basta então
executar make para compilar e make install para instalar.
Eu venho usando o cmake de maneira bem cut and paste no meu mestrado por causa
do CGAL. Decidi estudar um pouco mais sobre esse sistema e escrever sobre as
principais componentes.
Geração de executável
A principal função presente no cmake é a de gerar executáveis. Dados vários arquivos
de código-fonte, por exemplo a.c, b.c e c.c, sendo que o main está em a.c, uma
maneira de gerar um executável usando o gcc é o seguinte:
1
2
gcc -c b.c c.c
gcc a.c b.o c.o -o executavel
Com o cmake isso simplifica para
1 add_executable(executavel a.c b.c c.c)
Geração de biblioteca estática
Outra possibilidade é gerar bibliotecas estáticas. Se tivermos funções definidas nos
arquivos a.c e b.c e quisermos disponibilizá-las para outros programas utilizarem,
podemos fazer:
1
2
gcc -c a.c b.c
ar -cvq libab.a a.o b.o
https://kuniga.wordpress.com/2011/06/05/cmake/2011/05/29/shaders-para-o-brl-cad/
http://www.lrde.epita.fr/~adl/autotools.html
http://www.cmake.org/
https://kuniga.files.wordpress.com/2021/05/cmake.png
Para que um programa c.c possa usá-la, fazemos a linkagem da seguinte maneira:
1
gcc c.c -o executavel -L/caminho/para/libab/ -
lab
que é equivalente a:
1
gcc c.c -o executavel
/caminho/para/libab/libab.a
No cmake essas tarefas podem ser realizadas pelos seguintes comandos
1
2
3
add_library(libab a.c b.c)
add_executable(executavel c.c)
target_link_libraries(executavel libab)
Uma excelente referência sobre bibliotecas no linux é a do yolinux.com
Dependências
Agora, suponha que queremos linkar o nosso código a uma biblioteca já compilada.
Vamos supor que essa biblioteca, chamada libxyz.a, esteja
em /home/jose/programa/lib e o cabeçalho com as funções, chamado xyz.h, esteja
em /home/jose/programa/include.
Fazendo manualmente ficaríamos com algo do tipo
1
gcc -I/home/jose/programa/include -L/home/jose/programa/lib -
lxyz c.c -o executavel
Uma das maneiras de se encontrar uma biblioteca usando o cmake é da seguinte
maneira:
1
find_library(xyz_library NAMES xyz PATHS
/home/jose/programa/lib)
No exemplo acima, xyz_library é um nome qualquer para nos referenciarmos à
biblioteca. Em NAMES colocamos o nome da biblioteca sem o prefixo lib e a extensão
(por exemplo, libxyz.a vira xyz) em PATHS o caminho para essa biblioteca (PS.:
podemos colocar vários caminhos se a priori não sabemos onde a
biblioteca libzyx.a está).
Para fazer a ligação basta fazer:
1 target_link_libraries(executavel ${xyz_library})
http://www.yolinux.com/TUTORIALS/LibraryArchives-%20StaticAndDynamic.html
Para encontrar o cabeçalho com as funções, usamos
1
find_path(xyz_include NAMES xyz.h PATHS
/home/jose/programa/include)
Para informar ao compilador o caminho de xyz.h, basta fazer
1 include_directories(${xyz_includes})
Geralmente a busca por bibliotecas externas é modularizada para haver re-uso de
código. Para cada biblioteca externa, podemos definir um arquivo com nome
descritivo e extensão cmake. Por exemplo, suponha que queremos encontrar a
biblioteca Boost. Podemos definir um arquivo FindBOOST.cmake contendo código para
encontrar as bibliotecas e os cabeçalhos.
Cada um desses arquivos são postos em um diretório separado, que deverá ser salvo
na variável interna do cmake chamada CMAKE_MODULE_PATH. Um modo de fazer isso
é:
1
set(CMAKE_MODULE_PATH
"/caminho/para/os/arquivos/Find/")
Para executar os comandos desse arquivo, dentro de qualquer CMakeLists.txt dentro
do projeto, basta fazer algo como:
1 include(FindBOOST)
Sub-diretórios
Em geral cria-se um arquivo CMakeLists.txt por diretório. Para que o cmake
processe esses arquivos, os diretórios pais devem informá-lo com o
comando add_subdirectories. Se por exemplo quisermos incluir os
diretórios sub1 e sub2 filhos do diretório atual, basta incluir as seguintes linhas:
1
2
add_subdirectories(sub1)
add_subdirectories(sub2)
Compilação de código
É possível controlar o modo como a compilação é feita com o cmake. Um dos
principais meios para se fazer isso é através das variáveis CMAKE_C_FLAGS (para C)
e CMAKE_CXX_FLAGS (para C++).
Ao fazer:
1 set(CMAKE_C_FLAGS -Wall -Werror)
A próxima vez que o um programa C for compilado, essas flags serão adicionadas à
compilação. Para verificar isso, uma flag muito interessante a ser setada no comando
make, é o VERBOSE. Ao setar essa variável, toda vez que você executar o comando
make, ele exibirá os comandos de compilação que estão sendo executados.
1 make VERBOSE=1
Ele é bastante útil também para “debugar” um arquivo do tipo CMakeLists.txt, para
ver se ele está gerando comandos de compilação do jeito que esperamos.
Integração do cmake com o emacs
(Seção adicionada em 6 de Junho de 2011)
Nesse wiki do cmake há dicas para configuração do emacs para colorir corretamente
arquivos do tipo CMakeLists.txt e .cmake. Geralmente o emacs vem configurado
por padrão, mas em todo caso, basta baixar o arquivo cmake-mode.el e adicionar as
seguintes linhas no arquivo de configuração:
1
2
3
4
5
6
7
8
; Add cmake listfile names to the mode list.
(setq auto-mode-alist
(append
'(("CMakeLists\\.txt\\'" . cmake-mode))
'(("\\.cmake\\'" . cmake-mode))
auto-mode-alist))
(autoload 'cmake-mode "~/Downloads/cmake-mode.el"
t)
Troque Downloads pelo local onde você baixou o cmake-mode.el.
Se você usa abas no emacs, ao abrir vários arquivos CMakeLists.txt, eles serão
chamados de CMakeLists.txt, CMakeLists.txt<2>, CMakeLists.txt<3> e assim por
diante. Isso é bem incômodo, pois você sempre tem que olhar o conteúdo para ver de
qual CMakeLists se trata.
Para resolver esse problema, adicione a seguinte rotina no seu arquivo de
configurações. Ela adiciona um prefixo contendo o caminho de cada arquivo. Muito
útil!
1
2
3
;; uniquify.el is a helper routine to help give buffer names a
better unique name.
(when (load "uniquify" 'NOERROR)
(require 'uniquify)
http://www.itk.org/Wiki/Main_Page
http://www.cmake.org/CMakeDocs/cmake-mode.el
4
5
6
(setq uniquify-buffer-name-style 'forward)
;(setq uniquify-buffer-name-style 'post-forward)
)
Leitura Complementar
Ao invés de reunir uma série de referências, deixo apenas esse post do stackoverflow
para maior abrangência: cmake tutorial
http://stackoverflow.com/questions/2186110/cmake-tutorial