cmake: Using symlinks on unix like os'es for dependencies

Fixes: #8380

This commit fixes the side-effect of PR #8211 where a 'ninja clean'
would try to remove dependency folders.
Changes:
- Symlinks are created during build and CMake targets now depends on
  the symlinks. Thus, same behavior is achived with regards to
  dependency handling, while at the same time, the output can be
  cleaned as the dependencies are now attached to the symlinks.
- Dependencies have been changed so that generation of json files
  depends on the trigger file and CMake depends upon the subdir txt
  file. This prevents additional CMake runs after a clean.

Signed-off-by: Torsten Rasmussen <torsten.rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2018-06-14 22:27:17 +02:00 committed by Carles Cufí
commit 080e32efc5
2 changed files with 51 additions and 24 deletions

View file

@ -361,14 +361,20 @@ set(syscalls_subdirs_txt ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls_sub
# handling. The trigger file will update when a folder is added / removed.
set(syscalls_subdirs_trigger ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls_subdirs.trigger)
if(NOT (${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows))
set(syscalls_links --create-links ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls_links)
endif()
# When running CMake it must be ensured that all dependencies are correctly acquired.
execute_process(
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/subfolder_list.py
--directory ${ZEPHYR_BASE}/include # Walk this directory
--out-file ${syscalls_subdirs_txt} # Write this file
)
--directory ${ZEPHYR_BASE}/include # Walk this directory
--out-file ${syscalls_subdirs_txt} # Write file with discovered folder
--trigger ${syscalls_subdirs_trigger} # Trigger file that is used for json generation
${syscalls_links} # If defined, create symlinks for dependencies
)
file(STRINGS ${syscalls_subdirs_txt} PARSE_SYSCALLS_PATHS_DEPENDS)
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows)
@ -383,36 +389,37 @@ else()
# The syscall parsing depends on the folders in order to detect add/removed/modified files.
# When a folder is removed, CMake will try to find a target that creates that dependency.
# This command sets up the target for CMake to find.
# With out this code, CMake will fail with the following error:
# Without this code, CMake will fail with the following error:
# <folder> needed by '<target>', missing and no known rule to make it
# when a folder is removed.
add_custom_command(OUTPUT ${PARSE_SYSCALLS_PATHS_DEPENDS}
COMMAND ${CMAKE_COMMAND} -E echo ""
COMMENT "Preparing syscall dependency handling"
)
)
add_custom_command(
OUTPUT
${syscalls_subdirs_txt}
${syscalls_subdirs_trigger}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/subfolder_list.py
--directory ${ZEPHYR_BASE}/include # Walk this directory
--out-file ${syscalls_subdirs_txt} # Write this file
--trigger ${syscalls_subdirs_trigger} # Trigger file that will result in CMake rerun
--out-file ${syscalls_subdirs_txt} # Write file with discovered folder
--trigger ${syscalls_subdirs_trigger} # Trigger file that is used for json generation
${syscalls_links} # If defined, create symlinks for dependencies
DEPENDS ${PARSE_SYSCALLS_PATHS_DEPENDS}
)
)
# Ensure trigger file always exists when specifying CMake dependency.
if(NOT EXISTS ${syscalls_subdirs_trigger})
file(WRITE ${syscalls_subdirs_trigger} "")
# Ensure subdir file always exists when specifying CMake dependency.
if(NOT EXISTS ${syscalls_subdirs_txt})
file(WRITE ${syscalls_subdirs_txt} "")
endif()
# On other OS'es, modifying a file is reflected on the folder timestamp and hence detected
# when using depend on directory level.
# Thus CMake only needs to re-run when sub-directories are added / removed, which is indicated
# using a trigger file.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${syscalls_subdirs_trigger})
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${syscalls_subdirs_txt})
endif()
add_custom_command(
@ -421,9 +428,9 @@ add_custom_command(
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/parse_syscalls.py
--include ${ZEPHYR_BASE}/include # Read files from this dir
--json-file ${syscalls_json} # Write this file
DEPENDS ${syscalls_subdirs_txt} ${PARSE_SYSCALLS_HEADER_DEPENDS}
--include ${ZEPHYR_BASE}/include # Read files from this dir
--json-file ${syscalls_json} # Write this file
DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS}
)
add_custom_target(syscall_list_h_target DEPENDS ${syscall_list_h})

View file

@ -24,6 +24,8 @@ def main():
parser.add_argument('-d', '--directory', required=True,
help='Directory to walk for sub-directory discovery')
parser.add_argument('-c', '--create-links', required=False,
help='Create links for each directory found in directory given')
parser.add_argument('-o', '--out-file', required=True,
help='File to write containing a list of all directories found')
parser.add_argument('-t', '--trigger-file', required=False,
@ -32,11 +34,27 @@ def main():
args = parser.parse_args()
dirlist = []
dirlist.extend(args.directory)
if(args.create_links is not None):
if not os.path.exists(args.create_links):
os.makedirs(args.create_links)
directory = args.directory
symlink = args.create_links + os.path.sep + directory.replace(os.path.sep, '_')
if not os.path.exists(symlink):
os.symlink(directory, symlink)
dirlist.extend(symlink)
else:
dirlist.extend(args.directory)
dirlist.extend(os.linesep)
for root, dirs, files in os.walk(args.directory):
for subdir in dirs:
dirlist.extend(os.path.join(root, subdir))
if(args.create_links is not None):
directory = os.path.join(root, subdir)
symlink = args.create_links + os.path.sep + directory.replace(os.path.sep, '_')
if not os.path.exists(symlink):
os.symlink(directory, symlink)
dirlist.extend(symlink)
else:
dirlist.extend(os.path.join(root, subdir))
dirlist.extend(os.linesep)
new = ''.join(dirlist)
@ -46,13 +64,15 @@ def main():
with open(args.out_file, 'r') as fp:
existing = fp.read()
if new != existing:
touch(args.trigger_file)
# Always write the file to ensure dependencies to changed files are updated
with open(args.out_file, 'w') as fp:
fp.write(new)
if new != existing:
with open(args.out_file, 'w') as fp:
fp.write(new)
else:
with open(args.out_file, 'w') as fp:
fp.write(new)
# Always touch trigger file to ensure json files are updated
touch(args.trigger_file)
if __name__ == "__main__":
main()