6

I'm using asn1c in order to produce from one or more .asn1 files a series of .h and .c files into a given folder.

These C files have no correspondence in names with the original asn1 files.

These files must be linked together with mine in order to obtain a working executable. I'd love to be able to:

  • Automatically generate the files in the build directory to avoid polluting the rest of the project (probably done with add_custom_target)
  • Specify the dependency of my executable on those files, so that the asn1c executable is automatically run if the files are missing or if one of the .asn1 files is updated.
  • Automatically add ALL generated files to the compilation of my executable.

Since the generated files are not known in advance it's ok to just glob whatever the contents of the output directory of the asn1c command - as long as the directory is not empty I'm happy.

Svalorzen
  • 5,353
  • 3
  • 30
  • 54

1 Answers1

5

CMake expects complete list of sources to be passed to add_executable(). That is, you cannot glob files generated at build stage - it would be too late.

You have several ways for handle generating source files without knowing their names in advance:

  1. Generate files at configuration stage with execute_process. After that you may use file(GLOB) for collect source names and pass them to add_executable():

    execute_process(COMMAND asn1c <list of .asn1 files>)
    file(GLOB generated_sources "${CMAKE_CURRENT_BINARY_DIR}/*.c")
    add_executable(my_exe <list of normal sources> ${generated_sources})
    

    If input files for generation (.asn1 in your case) are not intended to be changed in the future, this is the most simple approach which just works.

    If you intend to change input files and expect CMake to detect these changings and regenerate source, some more action should be taken. E.g., you may first copy input files into build directory with configure_file(COPY_ONLY). In that case input files will be tracked, and CMake will rerun if they are changed:

    set(build_input_files) # Will be list of files copied into build tree
    foreach(input_file <list of .asn1 files>)
        # Extract name of the file for generate path of the file in the build tree
        get_filename_component(input_file_name ${input_file} NAME)
        # Path to the file created by copy
        set(build_input_file ${CMAKE_CURRENT_BINARY_DIR}/${input_file_name})
        # Copy file
        configure_file(${input_file} ${build_input_file} COPY_ONLY)
        # Add name of created file into the list
        list(APPEND build_input_files ${build_input_file})
    endforeach()
    
    execute_process(COMMAND asn1c ${build_input_files})
    file(GLOB generated_sources "${CMAKE_CURRENT_BINARY_DIR}/*.c")
    add_executable(my_exe <list of normal sources> ${generated_sources})
    
  2. Parse input files for determine, which files would be created from them. Not sure whether it works with .asn1, but for some formats this works:

    set(input_files <list of .asn1 files>)
    execute_process(COMMAND <determine_output_files> ${input_files}
        OUTPUT_VARIABLE generated_sources)
    add_executable(my_exe <list of normal sources> ${generated_sources})
    add_custom_command(OUTPUT ${generated_sources}
        COMMAND asn1c ${input_files}
        DEPENDS ${input_files})
    

    In that case CMake will detect changes in input files (but in case of modification of list of generated source files you need to rerun cmake manually).

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • The real problem with this is that I also use `CMake` to actually build the `asn1c` executable, so I cannot run it before the build phase. – Svalorzen May 20 '17 at 05:43
  • 1
    You may build `asn1c` as subproject at *configuration stage* with `execute_process()`. This looks like a good decision: no needs to defer build everything at *build stage*. – Tsyvarev May 20 '17 at 07:14