CMake does not find custom command “ls”

2019-07-29 10:01发布

问题:

I try to run some basic commands for my CLion projects, but it just doesn't work. Here is my CMake setting.

cmake_minimum_required(VERSION 3.6)
project(hello)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.cpp)
add_executable(hello ${SOURCE_FILES})

add_custom_command(OUTPUT hello.out
        COMMAND ls -l hello
        DEPENDS hello)

add_custom_target(run_hello_out
        DEPENDS hello.out)

I got the following error messages when running run_hello_out in CLion.

[100%] Generating hello.out
process_begin: CreateProcess(NULL, ls -l hello, ...) failed.
make (e=2): The system cannot find the file specified.
mingw32-make.exe[3]: *** [hello.out] Error 2
mingw32-make.exe[2]: *** [CMakeFiles/run_hello_out.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles/run_hello_out.dir/rule] Error 2
mingw32-make.exe: *** [run_hello_out] Error 2
CMakeFiles\run_hello_out.dir\build.make:59: recipe for target 'hello.out' failed
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/run_hello_out.dir/all' failed
CMakeFiles\Makefile2:73: recipe for target 'CMakeFiles/run_hello_out.dir/rule' failed
Makefile:117: recipe for target 'run_hello_out' failed

It is supposed to run "ls -l hello" and see the results in either build window or run window.

回答1:

The Problem

CMake doesn't guaranty a shell context for its COMMAND calls and it doesn't automatically search for the executable given with COMMAND itself.

It mainly puts the given command into the generated build environment and depends on how it's handled there.

In your case I assume you/CLion is running cmake and mingw32-make in a MS Windows cmd shell. In this case you would have had to use the dir instead of the ls command:

add_custom_target(
    run_hello_out
    COMMAND dir $<TARGET_FILE_NAME:hello>
    DEPENDS hello
)

Possible Soltions

I see three possible solutions. Either

  1. Provide a bash shell context

    include(FindUnixCommands)
    
    if (BASH)
        add_custom_target(
            run_hello_out
            COMMAND ${BASH} -c "ls -l hello"
            DEPENDS hello
        )
    endif()
    
  2. Use CMake's shell abstraction cmake -E (only limited number of commands, e.g. no ls equivalent)

    add_custom_target(
        run_hello_out
        COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_FILE:hello>
        DEPENDS hello
    )
    
  3. Search for the executable with find_program().

    find_program(LS ls)
    
    if (LS)
        add_custom_target(
            run_hello_out
            COMMAND ${LS} -l hello
            DEPENDS hello
    endif()
    

Reference

  • How to use redirection in cmake add_test


回答2:

Somehow ls doesn't work even I set up the global path correctly. CMake needs full path. The following works and solves the issue.

add_custom_command(OUTPUT hello.out
        COMMAND "C:\\FULL PATH HERE\\ls" -l hello
        DEPENDS hello)


标签: windows cmake