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. # 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) 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. # When running CMake it must be ensured that all dependencies are correctly acquired.
execute_process( execute_process(
COMMAND COMMAND
${PYTHON_EXECUTABLE} ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/subfolder_list.py ${ZEPHYR_BASE}/scripts/subfolder_list.py
--directory ${ZEPHYR_BASE}/include # Walk this directory --directory ${ZEPHYR_BASE}/include # Walk this directory
--out-file ${syscalls_subdirs_txt} # Write this file --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) file(STRINGS ${syscalls_subdirs_txt} PARSE_SYSCALLS_PATHS_DEPENDS)
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows) if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Windows)
@ -383,7 +389,7 @@ else()
# The syscall parsing depends on the folders in order to detect add/removed/modified files. # 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. # 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. # 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 # <folder> needed by '<target>', missing and no known rule to make it
# when a folder is removed. # when a folder is removed.
add_custom_command(OUTPUT ${PARSE_SYSCALLS_PATHS_DEPENDS} add_custom_command(OUTPUT ${PARSE_SYSCALLS_PATHS_DEPENDS}
@ -393,26 +399,27 @@ else()
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${syscalls_subdirs_txt} ${syscalls_subdirs_trigger}
COMMAND COMMAND
${PYTHON_EXECUTABLE} ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/subfolder_list.py ${ZEPHYR_BASE}/scripts/subfolder_list.py
--directory ${ZEPHYR_BASE}/include # Walk this directory --directory ${ZEPHYR_BASE}/include # Walk this directory
--out-file ${syscalls_subdirs_txt} # Write this file --out-file ${syscalls_subdirs_txt} # Write file with discovered folder
--trigger ${syscalls_subdirs_trigger} # Trigger file that will result in CMake rerun --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} DEPENDS ${PARSE_SYSCALLS_PATHS_DEPENDS}
) )
# Ensure trigger file always exists when specifying CMake dependency. # Ensure subdir file always exists when specifying CMake dependency.
if(NOT EXISTS ${syscalls_subdirs_trigger}) if(NOT EXISTS ${syscalls_subdirs_txt})
file(WRITE ${syscalls_subdirs_trigger} "") file(WRITE ${syscalls_subdirs_txt} "")
endif() endif()
# On other OS'es, modifying a file is reflected on the folder timestamp and hence detected # On other OS'es, modifying a file is reflected on the folder timestamp and hence detected
# when using depend on directory level. # when using depend on directory level.
# Thus CMake only needs to re-run when sub-directories are added / removed, which is indicated # Thus CMake only needs to re-run when sub-directories are added / removed, which is indicated
# using a trigger file. # 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() endif()
add_custom_command( add_custom_command(
@ -423,7 +430,7 @@ add_custom_command(
${ZEPHYR_BASE}/scripts/parse_syscalls.py ${ZEPHYR_BASE}/scripts/parse_syscalls.py
--include ${ZEPHYR_BASE}/include # Read files from this dir --include ${ZEPHYR_BASE}/include # Read files from this dir
--json-file ${syscalls_json} # Write this file --json-file ${syscalls_json} # Write this file
DEPENDS ${syscalls_subdirs_txt} ${PARSE_SYSCALLS_HEADER_DEPENDS} DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS}
) )
add_custom_target(syscall_list_h_target DEPENDS ${syscall_list_h}) 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, parser.add_argument('-d', '--directory', required=True,
help='Directory to walk for sub-directory discovery') 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, parser.add_argument('-o', '--out-file', required=True,
help='File to write containing a list of all directories found') help='File to write containing a list of all directories found')
parser.add_argument('-t', '--trigger-file', required=False, parser.add_argument('-t', '--trigger-file', required=False,
@ -32,10 +34,26 @@ def main():
args = parser.parse_args() args = parser.parse_args()
dirlist = [] dirlist = []
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(args.directory)
dirlist.extend(os.linesep) dirlist.extend(os.linesep)
for root, dirs, files in os.walk(args.directory): for root, dirs, files in os.walk(args.directory):
for subdir in dirs: for subdir in dirs:
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.path.join(root, subdir))
dirlist.extend(os.linesep) dirlist.extend(os.linesep)
@ -47,12 +65,14 @@ def main():
existing = fp.read() existing = fp.read()
if new != existing: if new != existing:
touch(args.trigger_file) with open(args.out_file, 'w') as fp:
fp.write(new)
# Always write the file to ensure dependencies to changed files are updated else:
with open(args.out_file, 'w') as fp: with open(args.out_file, 'w') as fp:
fp.write(new) fp.write(new)
# Always touch trigger file to ensure json files are updated
touch(args.trigger_file)
if __name__ == "__main__": if __name__ == "__main__":
main() main()