build: CMake and ns3 fixes and improvements

Includes:
- fix python warnings and wrap pkgconfig_interface_include_directories in quotes to treat it as a string
- prevent failure when Python is not found
- refactor python bindings checks and error messages
- export 3rd-party include directories and linked libraries
    - Adding a NS3_REEXPORT_THIRD_PARTY_LIBRARIES option to always export include directories and libraries used by a module, making it automatically available to 3rd-party modules
    - Making NS3_REEXPORT_THIRD_PARTY_LIBRARIES option enabled by default
- replace colliding shortcuts with list of non-ambiguous shortcuts
- remove unnecessary code blocks from click
- warn users that doxygen target requires examples and tests
    - These are used to generate introspected documentation and guarantee proper dependency checking and build order
This commit is contained in:
Gabriel Ferreira
2022-01-26 11:51:50 -03:00
parent e1e07f2ffd
commit 113c3744fc
8 changed files with 259 additions and 80 deletions

90
ns3
View File

@@ -279,24 +279,24 @@ def parse_args(argv):
return args
def check_build_profile(output_directory):
def check_c4che_data(output_directory):
# Check the c4cache for the build type (in case there are multiple cmake cache folders
c4che_path = os.sep.join([output_directory, "c4che", "_cache.py"])
build_profile = None
ns3_version = None
ns3_modules = None
ns3_modules_tests = []
ns3_modules_apiscan = []
ns3_modules_bindings = []
enable_sudo = False
ns3_modules = None
c4che_info = {"BUILD_PROFILE" : None,
"VERSION" : None,
"ENABLE_EXAMPLES" : False,
"ENABLE_SUDO" : False,
"ENABLE_TESTS" : False,
}
if output_directory and os.path.exists(c4che_path):
c4che_info = {}
exec(open(c4che_path).read(), globals(), c4che_info)
build_profile = c4che_info["BUILD_PROFILE"]
ns3_version = c4che_info["VERSION"]
ns3_modules = c4che_info["NS3_ENABLED_MODULES"]
if "ENABLE_SUDO" in c4che_info:
enable_sudo = c4che_info["ENABLE_SUDO"]
if ns3_modules:
if c4che_info["ENABLE_TESTS"]:
ns3_modules_tests = [x + "-test" for x in ns3_modules]
@@ -305,7 +305,7 @@ def check_build_profile(output_directory):
if "ENABLE_SCAN_PYTHON_BINDINGS" in c4che_info and c4che_info["ENABLE_SCAN_PYTHON_BINDINGS"]:
ns3_modules_apiscan = [x + "-apiscan" for x in ns3_modules]
ns3_modules = ns3_modules + ns3_modules_tests + ns3_modules_apiscan + ns3_modules_bindings
return build_profile, ns3_version, ns3_modules, enable_sudo
return c4che_info, ns3_modules
def print_and_buffer(message):
@@ -535,10 +535,13 @@ def get_program_shortcuts(build_profile, ns3_version):
# We can now build a map to simplify things for users (at this point we could remove versioning prefix/suffix)
ns3_program_map = {}
longest_shortcut_map = {}
for program in programs_dict["ns3_runnable_programs"]:
if "pch_exec" in program:
continue
temp_path = program.replace(out_dir, "").split(os.sep)
temp_path.pop(0) # remove first path separator
# Remove version prefix and build type suffix from shortcuts (or keep them too?)
temp_path[-1] = temp_path[-1].replace("-" + build_profile, "").replace("ns" + ns3_version + "-", "")
@@ -555,14 +558,35 @@ def get_program_shortcuts(build_profile, ns3_version):
source_shortcut = True
program = program.strip()
longest_shortcut = None
while len(temp_path):
# Shortcuts: /src/aodv/examples/aodv can be accessed with aodv/examples/aodv, examples/aodv, aodv
shortcut_path = os.sep.join(temp_path)
ns3_program_map[shortcut_path] = program
if not longest_shortcut:
longest_shortcut = shortcut_path
# Store longest shortcut path for collisions
if shortcut_path not in longest_shortcut_map:
longest_shortcut_map[shortcut_path] = [longest_shortcut]
else:
longest_shortcut_map[shortcut_path].append(longest_shortcut)
ns3_program_map[shortcut_path] = [program]
if source_shortcut:
ns3_program_map[shortcut_path + ".cc"] = program
cc_shortcut_path = shortcut_path + ".cc"
ns3_program_map[cc_shortcut_path] = [program]
# Store longest shortcut path for collisions
if cc_shortcut_path not in longest_shortcut_map:
longest_shortcut_map[cc_shortcut_path] = [longest_shortcut]
else:
longest_shortcut_map[cc_shortcut_path].append(longest_shortcut)
temp_path.pop(0)
# Filter collisions
collisions = list(filter(lambda x: x if len(x[1]) > 1 else None, longest_shortcut_map.items()))
for (colliding_shortcut, longest_shortcuts) in collisions:
ns3_program_map[colliding_shortcut] = longest_shortcuts
if programs_dict["ns3_runnable_scripts"]:
scratch_scripts = glob.glob(os.path.join(ns3_path, "scratch", "*.py"), recursive=True)
@@ -573,7 +597,7 @@ def get_program_shortcuts(build_profile, ns3_version):
program = program.strip()
while len(temp_path):
shortcut_path = os.sep.join(temp_path)
ns3_program_map[shortcut_path] = program
ns3_program_map[shortcut_path] = [program]
temp_path.pop(0)
return ns3_program_map
@@ -589,12 +613,12 @@ def cmake_check_version():
cmake = shutil.which("cmake")
if not cmake:
print("Error: CMake not found; please install version 3.10 or greater, or modify $PATH")
exit(-1)
exit(1)
cmake_output = subprocess.check_output([cmake, "--version"]).decode("utf-8")
version = re.findall("version (.*)", cmake_output)[0]
if parse_version(version) < parse_version("3.10.0"):
print("Error: CMake found at %s but version %s is older than 3.10" % (cmake, version))
exit(-1)
exit(1)
return cmake, version
@@ -970,18 +994,26 @@ def main():
# We end things earlier when cleaning
return
# Docs options become cmake targets
if args.docs:
args.build = [args.docs] if args.docs != "all" else ["sphinx", "doxygen"]
# Installation and uninstallation options become cmake targets
if args.install:
args.build = ['install']
if args.uninstall:
args.build = ['uninstall']
# Get build profile
build_profile, ns3_version, ns3_modules, enable_sudo = check_build_profile(out_dir)
# Get build profile and other settings
c4che_info, ns3_modules = check_c4che_data(out_dir)
build_profile = c4che_info["BUILD_PROFILE"]
enable_sudo = c4che_info["ENABLE_SUDO"]
ns3_version = c4che_info["VERSION"]
# Docs options become cmake targets
if args.docs:
args.build = [args.docs] if args.docs != "all" else ["sphinx", "doxygen"]
if "doxygen" in args.build and (not c4che_info["ENABLE_EXAMPLES"] or not c4che_info["ENABLE_TESTS"]):
print('The "./ns3 docs doxygen" and "./ns3 docs all" commands,\n'
'require examples and tests to generate introspected documentation.\n'
'Try "./ns3 docs doxygen-no-build" or enable examples and tests.')
exit(1)
if args.check_profile:
if build_profile:
@@ -1052,17 +1084,25 @@ def main():
# Now that CMake is configured, we can look for c++ targets in build-status.py
ns3_programs = get_program_shortcuts(build_profile, ns3_version)
def check_ambiguous_target(target_type, target_to_run, ns3_programs):
if len(ns3_programs[target_to_run]) > 1:
print('%s target "%s" is ambiguous. Try one of these: "%s"'
% (target_type, target_to_run, '", "'.join(ns3_programs[target_to_run])))
exit(1)
return ns3_programs[target_to_run][0]
# If we have a target to run, replace shortcut with full path or raise exception
if run_only or build_and_run:
if target_to_run in ns3_programs:
target_to_run = ns3_programs[target_to_run]
target_to_run = check_ambiguous_target("Run", target_to_run, ns3_programs)
else:
raise Exception("Couldn't find the specified program: %s" % target_to_run)
if "build" in args:
complete_targets = []
for target in args.build:
complete_targets.append(ns3_programs[target] if target in ns3_programs else target)
build_target = check_ambiguous_target("Build", target, ns3_programs) if target in ns3_programs else target
complete_targets.append(build_target)
args.build = complete_targets
del complete_targets
@@ -1108,7 +1148,7 @@ def main():
# Setup program as sudo
if enable_sudo or (args.run and args.enable_sudo):
sudo_step(args, target_to_run, set(ns3_programs.values()) if enable_sudo else set())
sudo_step(args, target_to_run, set(ns3_programs.values()[0]) if enable_sudo else set())
# Finally, we try to run it
if args.check or args.shell or run_only or build_and_run: