CMake通过shell脚本生成C头

时间:2013-02-11 02:17:35

标签: c cmake build-automation

我有一个shell脚本,它接受一个JSON文件并输出一个.h文件,我的一个目标依赖于该文件。似乎CMake的add_custom_command是我需要完成的,但是我无法生成头文件。我已经尝试过使用this postthis post中的信息考虑的所有组合。

以下是我可以创建的最简单的方法来重现我遇到的问题。

我的项目结构如下:

.
├── CMakeLists.txt
├── main.c
└── res
    ├── generate.sh
    └── input.json

的CMakeLists.txt


cmake_minimum_required(VERSION 2.8)
project(test)

set(TEST_DATA_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data.h)
add_custom_command(
    OUTPUT ${TEST_DATA_OUTPUT}
    COMMAND res/generate.sh h res/input.json ${TEST_DATA_OUTPUT}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "Generates the header file containing the JSON data."
)

# add the binary tree to the search path for include files so we
# will fine the generated files
include_directories(${CMAKE_CURRENT_BINARY_DIR})

set(SRCS main.c)
add_executable(test ${SRCS})

的main.c


#include <stdio.h>

#include "test_data.h"

int main(int argc, char** argv)
{
    printf("%s\n", TEST_DATA);
    return 0;
}

RES / generate.sh


#!/bin/sh
#
# Converts the JSON to a C header file to be used as a resource file.

print_usage()
{
cat << EOF
USAGE:
    $0 h INPUT

DESCRIPTION:
    Outputs JSON data to another format.

EOF
}

to_h()
{
cat << EOF
#ifndef TEST_DATA_H
#define TEST_DATA_H

static const char* TEST_DATA =
"$(cat "$1" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/"\n"/g')";

#endif // TEST_DATA_H
EOF
}

case "$1" in
h)
    if [ $# -eq 3 ] ; then
        to_h "$2" > "$3"
    elif [ $# -eq 2 ] ; then
        to_h "$2"
    else
        echo "no input file specified" 1>&2
    fi
    ;;
*)
    print_usage
    ;;
esac

exit 0

RES / input.json


{
    "1": {
        "attr1": "value1",
        "attr2": "value2"
    },
    "2": {
        "attr1": "value1",
        "attr2": "value2"
    }
}

2 个答案:

答案 0 :(得分:0)

这是一个示例CMakeLists.txt,它使用Ragel读取输入文件(nstrip.rl),生成输出文件(nstrip.c),并将输出文件编译/链接到二进制的。

set(RAGEL_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/nstrip.c)

add_executable(
  nstrip
    ${RAGEL_OUTPUT}
  )
set_target_properties(
  nstrip
  PROPERTIES
    COMPILE_FLAGS -std=c99
  )

find_program(RAGEL ragel)
add_custom_command(
  OUTPUT             ${RAGEL_OUTPUT}
  COMMAND            ${RAGEL} -G2 -o ${RAGEL_OUTPUT} nstrip.rl
  DEPENDS            nstrip.rl
  WORKING_DIRECTORY  ${CMAKE_CURRENT_SOURCE_DIR}
  COMMENT            "Ragel: Generating Statemachine"
  VERBATIM
  )

注意:

  • with DEPENDS该命令仅在依赖项实际更改时执行。
  • 这是为源外构建做好准备的,因为它将生成的文件放在CMAKE_CURRENT_BINARY_DIR中(即 build 树中的目录对应于上述CMakeLists的位置) source 树中的.txt),并将其用作可执行文件的输入。
  • 同样,它也执行命令,WORKING_DIRECTORY设置为上面的CMakeLists.txt所在的位置,因此您可以使用相对路径引用源文件(此处为nstrip.rl)(您也可以执行此操作)反过来说。)

对于您的情况,您需要告诉CMake在哪里找到标题:

# assuming you generate into the build tree
include_directories("${CMAKE_CURRENT_BINARY_DIR}")`

此外,如果生成可执行文件是一个存在于源树而不是$PATH的脚本,请忽略find_program并将脚本添加到DEPENDS。每当您更改输入文件(json)脚本本身时,CMake将自动触发标头的重建。

答案 1 :(得分:0)

现在我已经获得了更多使用CMake的经验,我回过头来看看我是否可以使用它。以下显示了需要更改的2行。

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6aa2ac6..5d80124 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,8 +2,7 @@ cmake_minimum_required(VERSION 2.8)
 project(test)

 set(TEST_DATA_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data.h)
-add_custom_command(
-    OUTPUT ${TEST_DATA_OUTPUT}
+add_custom_target(generate
     COMMAND res/generate.sh h res/input.json ${TEST_DATA_OUTPUT}
     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
     COMMENT "Generates the header file containing the JSON data."
@@ -15,3 +14,4 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})

 set(SRCS main.c)
 add_executable(test ${SRCS})
+add_dependencies(test generate)