Generic rule from makefile to CMake

2019-01-12 00:26发布

I am trying to "translate" the flowing vanilla makefile lines into CMake syntax.

SRCS = $(wildcard *.foo)
OBJS = $(SRCS:.foo=.bar)

my_rule: $(OBJS)

%.bar: %.foo
    make_bar_from_foo  $@  $<

Working ugly attempt

FILE(GLOB SRCS "*.foo")
SET(outFiles)
FOREACH(SRC ${SRCS})
    SET(OUTPUT_FILE_NAME "${SRC}.bar")

    ADD_CUSTOM_COMMAND(
      OUTPUT "${OUTPUT_FILE_NAME}"
      COMMAND make_bar_from_foo ${SRC} ${OUTPUT_FILE_NAME}
      DEPENDS "${SRC}")

    SET(outFiles ${outFiles} "${OUTPUT_FILE_NAME}")
ENDFOREACH(SRC)
ADD_CUSTOM_TARGET(my_rule ALL DEPENDS ${outFiles})

I understand that it's going to generate one command per file instead of something generic. Any simplest/cleanest way to do it?

3条回答
闹够了就滚
2楼-- · 2019-01-12 01:07

In general, with CMake you don't build all object files. Just add the right .foo files into the right CMake commands (add_library or add_executable) and CMake will handle it for you.

CMake is way more powerful compared to plain make. But you have to accept that this power comes with a change of how you use the tool.

查看更多
Evening l夕情丶
3楼-- · 2019-01-12 01:25

In CMake you can always declare your own compiler language. So in your case you can e.g. do:

cmake_minimum_required(VERSION 2.8)

project(MakeBarFromFoo NONE)

set(
   CMAKE_FOO_COMPILE_OBJECT 
       "make_bar_from_foo <SOURCE> <OBJECT>"
)

file(GLOB SRCS "*.foo")
add_library(my_rule OBJECT ${SRCS})
set_source_files_properties(${SRCS} PROPERTIES LANGUAGE FOO)

Then you can simply work with it as you would with other object library targets. But you will only get things like the .bar extension if you enable_language(FOO) (and that requires more work, see below).

Examples delivered with CMake itself are ASM or RC compilers.


The enable_language(FOO) Version

This needs four more files you could put in e.g. your project's CMake folder:

CMake\CMakeDetermineFOOCompiler.cmake

# Find the compiler
find_program(
    CMAKE_FOO_COMPILER 
        NAMES "make_bar_from_foo" 
        HINTS "${CMAKE_SOURCE_DIR}"
        DOC "FOO compiler" 
)
mark_as_advanced(CMAKE_FOO_COMPILER)

set(CMAKE_FOO_SOURCE_FILE_EXTENSIONS foo;FOO)
set(CMAKE_FOO_OUTPUT_EXTENSION .bar)
set(CMAKE_FOO_COMPILER_ENV_VAR "FOO")

# Configure variables set in this file for fast reload later on
configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeFOOCompiler.cmake.in
               ${CMAKE_PLATFORM_INFO_DIR}/CMakeFOOCompiler.cmake)

CMake\CMakeFOOCompiler.cmake.in

set(CMAKE_FOO_COMPILER "@CMAKE_FOO_COMPILER@")
set(CMAKE_FOO_COMPILER_LOADED 1)
set(CMAKE_FOO_SOURCE_FILE_EXTENSIONS @CMAKE_FOO_SOURCE_FILE_EXTENSIONS@)
set(CMAKE_FOO_OUTPUT_EXTENSION @CMAKE_FOO_OUTPUT_EXTENSION@)
set(CMAKE_FOO_COMPILER_ENV_VAR "@CMAKE_FOO_COMPILER_ENV_VAR@")

CMake\CMakeFOOInformation.cmake

# This file sets the basic flags for the FOO compiler
if(NOT CMAKE_FOO_COMPILE_OBJECT)
    set(CMAKE_FOO_COMPILE_OBJECT "<CMAKE_FOO_COMPILER> <SOURCE> <OBJECT>")
endif()
set(CMAKE_FOO_INFORMATION_LOADED 1)

CMake\CMakeTestFOOCompiler.cmake

# For now just do nothing in here
set(CMAKE_FOO_COMPILER_WORKS 1 CACHE INTERNAL "")

Then your CMakeLists.txt file just looks like this:

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(MakeBarFromFoo NONE)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMake")
enable_language(FOO)

file(GLOB SRCS "*.foo")
add_library(my_rule OBJECT ${SRCS})
查看更多
Emotional °昔
4楼-- · 2019-01-12 01:29

Your attempt is correct, and it hardly can be significantly improved.

This is just how CMake works: each of its "rules" is concrete; you cannot create a "template rule". The reason for that is platform independence: not every build systems supports "templates" for rules.

On the other side, CMake supports creation of the "rules" within functions/macros. So typing repeated parts can be easily reduced.

查看更多
登录 后发表回答