Diferença entre usar Makefile e CMake para compilar o código


288

Eu codifico em C / C ++ e uso um Makefile (GNU) para compilar o código. Eu posso fazer o mesmo com o CMake e obter um MakeFile. No entanto, qual é a diferença entre usar Makefile e CMake para compilar o código?


2
O cmake também pode produzir arquivos para usar o ninja
#

Respostas:


403

Make (ou melhor, um Makefile) é um sistema de compilação - ele dirige o compilador e outras ferramentas de compilação para criar seu código.

O CMake é um gerador de sistemas de construção. Pode produzir Makefiles, arquivos de compilação Ninja, projetos KDEvelop ou Xcode, soluções Visual Studio. Do mesmo ponto de partida, o mesmo arquivo CMakeLists.txt. Portanto, se você tem um projeto independente de plataforma, o CMake é uma maneira de torná-lo independente do sistema.

Se você tem desenvolvedores do Windows acostumados a desenvolvedores do Visual Studio e Unix que juram pelo GNU Make, o CMake é (um dos) caminhos a seguir.

Eu sempre recomendo usar o CMake (ou outro gerador de sistema de construção, mas o CMake é minha preferência pessoal) se você pretende que seu projeto seja multiplataforma ou amplamente utilizável. O próprio CMake também oferece alguns recursos interessantes, como detecção de dependência, gerenciamento de interface de biblioteca ou integração com CTest, CDash e CPack.

O uso de um gerador de sistema de construção torna seu projeto mais à prova de futuro. Mesmo se você for GNU-Make-only agora, e se depois decidir expandir para outras plataformas (seja Windows ou algo incorporado), ou apenas desejar usar um IDE?


5
@ rish Sim, essa é a essência. Note, no entanto, que existem mais maneiras de programar no Linux do que Makefiles - veja, por exemplo, QtCreator, KDEvelop, Ninja. Para cada uma delas, é "crie um projeto e mantenha-o sincronizado com o Makefile" ou "re-execute o CMake". E, como a resposta menciona, o CMake também tem outras funcionalidades, como descoberta de dependência (por exemplo find_package()) ou suporte a teste / empacotamento.
Angew não está mais orgulhoso de SO

3
Eu li que o CMake não pode criar makefiles não recursivos. Isso ainda é verdade?
Maxim Egorushkin

1
@Angew Não recursivo é quando o make é chamado uma vez com a árvore de dependência completa do projeto. Em vez de recursivo quando um makefile de nível superior chama makefiles de subprojetos em determinada ordem.
Maxim Egorushkin

3
Esta é uma fraqueza importante do CMake - o GNU make tem suas rugas, mas se você dedicar um tempo para aprendê-lo, é extremamente poderoso e versátil e funciona em uma enorme quantidade de plataformas. Não ter uma árvore de dependência completa para analisar é uma falha grave, basta procurar no Google por 'make recursiva considerada prejudicial'.
Erik Alapää

1
@ ErikAlapää Vou ler o artigo em detalhes, mas à primeira vista - eles parecem estar falando sobre a forma recursiva, onde a profundidade da recursão é orientada por dados (isto é, depende da profundidade do diretório de origem etc.). Esse não é o caso do CMake: a profundidade total de invocações de marca é sempre 3, independentemente da estrutura do projeto. Apenas alguns bits são delegados a um submakefile em vez de todos em um, mas isso não reflete a estrutura do projeto de forma alguma. Além disso, os submakefiles não são realmente "independentes" e, portanto, não sofrem o problema de dependência excessiva / insuficiente.
Angew não se orgulha mais de SO

39

A afirmação de que o CMake é um "gerador de compilação" é um equívoco comum.

Não é tecnicamente errado; apenas descreve como funciona, mas não o que faz.

No contexto da pergunta, eles fazem o mesmo: pegue um monte de arquivos C / C ++ e os transforme em binários.

Então, qual é a diferença real?

  • O CMake é muito mais de alto nível. Ele foi adaptado para compilar C ++, para o qual você escreve muito menos código de compilação, mas também pode ser usado para compilação de uso geral. maketambém possui algumas regras C / C ++ integradas, mas são principalmente inúteis.

  • CMakefaz uma compilação em duas etapas: gera um script de compilação de baixo nível em ninjaou em makemuitos outros geradores e, em seguida, você o executa. Todas as partes do script de shell que normalmente são empilhadas Makefilesão executadas apenas no estágio de geração. Assim, a CMakeconstrução pode ter ordens de magnitude mais rápidas.

  • A gramática de CMakeé muito mais fácil de suportar para ferramentas externas do que as de make .

  • Depois de makecriar um artefato, ele esquece como foi construído. De quais fontes ele foi criado, quais sinalizadores do compilador? CMakerastreia, makedeixa com você. Se uma das fontes da biblioteca foi removida desde a versão anterior Makefile, makenão será reconstruída.

  • Moderno CMake(a partir da versão 3.algo) funciona em termos de dependências entre "destinos". Um destino ainda é um único arquivo otput (infelizmente), mas pode ter dependências transitivas ("pública" / "interface" em termos do CMake)). Essas dependências transitivas podem ser expostas ou ocultas dos pacotes dependentes. CMakeirá gerenciar diretórios para você também. Com make, você fica preso no nível arquivo por arquivo e gerencia diretórios à mão.

Você pode codificar algo makeusando arquivos de sinalização para cobrir as duas últimas lacunas, mas está por sua conta. makecontém um idioma completo de Turing (até dois, às vezes três contando Guile ), e todos eles são horríveis.

Para ser honesto, isso é o que CMakee maketêm em comum - suas línguas são bastante horrível:

  • Eles não têm tipos;
  • sem matrizes, apenas cordas separadas por espaço, escapando assim do inferno;
  • você normalmente passa argumentos para funções definindo variáveis ​​globais; (isso está sendo abordado no CMake moderno - as variáveis ​​podem ter um espaço para nome agora; um destino é um espaço para nome para suas propriedades)
  • referir-se a uma variável indefinida é silenciosamente ignorado por padrão;

começar com.

Mas CMakevocê escreve muito menos linhas de código.


1
Algumas boas informações aqui, mas uma observação está completamente errada: cmake tem um tipo LIST, pois com funções LIST apropriadas, que são cruciais para muitas tarefas do sistema de compilação, uma pequena diferença: cmake.org/cmake/help/git-master/command / list.html
solvingJ

Eu não chamaria isso de "completamente" errado, mas obrigado pela correção.
Victor Sergienko
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.