LibTimeZone+Meta: Add plumbing for an IANA Time Zone Database generator

The IANA Time Zone Database contains data needed, at least, for various
JavaScript objects. This adds plumbing for a parser and code generator
for this data. The generated data will be made available by LibTimeZone,
much like how UCD and CLDR data is available through LibUnicode.
This commit is contained in:
Timothy Flynn 2021-12-22 16:33:38 -05:00 committed by Linus Groh
parent 9ba386a7bb
commit 8669b25cea
Notes: sideshowbarker 2024-07-17 21:26:55 +09:00
8 changed files with 184 additions and 6 deletions

View File

@ -9,5 +9,6 @@ serenity_option(ENABLE_ALL_THE_DEBUG_MACROS OFF CACHE BOOL "Enable all debug mac
serenity_option(ENABLE_ALL_DEBUG_FACILITIES OFF CACHE BOOL "Enable all noisy debug symbols and options. Not recommended for normal developer use")
serenity_option(ENABLE_COMPILETIME_HEADER_CHECK OFF CACHE BOOL "Enable compiletime check that each library header compiles stand-alone")
serenity_option(ENABLE_TIME_ZONE_DATABASE_DOWNLOAD ON CACHE BOOL "Enable download of the IANA Time Zone Database at build time")
serenity_option(ENABLE_UNICODE_DATABASE_DOWNLOAD ON CACHE BOOL "Enable download of Unicode UCD and CLDR files at build time")
serenity_option(INCLUDE_WASM_SPEC_TESTS OFF CACHE BOOL "Download and include the WebAssembly spec testsuite")

View File

@ -0,0 +1,88 @@
include(${CMAKE_CURRENT_LIST_DIR}/utils.cmake)
set(TZDB_PATH "${CMAKE_BINARY_DIR}/TZDB" CACHE PATH "Download location for TZDB files")
set(TZDB_VERSION 2021e)
set(TZDB_VERSION_FILE "${TZDB_PATH}/version.txt")
set(TZDB_ZIP_URL "https://data.iana.org/time-zones/releases/tzdata${TZDB_VERSION}.tar.gz")
set(TZDB_ZIP_PATH "${TZDB_PATH}/tzdb.tar.gz")
set(TZDB_AFRICA_SOURCE africa)
set(TZDB_AFRICA_PATH "${TZDB_PATH}/${TZDB_AFRICA_SOURCE}")
set(TZDB_ANTARCTICA_SOURCE antarctica)
set(TZDB_ANTARCTICA_PATH "${TZDB_PATH}/${TZDB_ANTARCTICA_SOURCE}")
set(TZDB_ASIA_SOURCE asia)
set(TZDB_ASIA_PATH "${TZDB_PATH}/${TZDB_ASIA_SOURCE}")
set(TZDB_AUSTRALASIA_SOURCE australasia)
set(TZDB_AUSTRALASIA_PATH "${TZDB_PATH}/${TZDB_AUSTRALASIA_SOURCE}")
set(TZDB_ETCETERA_SOURCE etcetera)
set(TZDB_ETCETERA_PATH "${TZDB_PATH}/${TZDB_ETCETERA_SOURCE}")
set(TZDB_EUROPE_SOURCE europe)
set(TZDB_EUROPE_PATH "${TZDB_PATH}/${TZDB_EUROPE_SOURCE}")
set(TZDB_NORTH_AMERICA_SOURCE northamerica)
set(TZDB_NORTH_AMERICA_PATH "${TZDB_PATH}/${TZDB_NORTH_AMERICA_SOURCE}")
set(TZDB_SOUTH_AMERICA_SOURCE southamerica)
set(TZDB_SOUTH_AMERICA_PATH "${TZDB_PATH}/${TZDB_SOUTH_AMERICA_SOURCE}")
function(extract_tzdb_file source path)
if(EXISTS "${TZDB_ZIP_PATH}" AND NOT EXISTS "${path}")
message(STATUS "Extracting TZDB ${source} from ${TZDB_ZIP_PATH}...")
execute_process(COMMAND tar -C "${TZDB_PATH}" -xf "${TZDB_ZIP_PATH}" "${source}" RESULT_VARIABLE tar_result)
if (NOT tar_result EQUAL 0)
message(FATAL_ERROR "Failed to unzip ${source} from ${TZDB_ZIP_PATH} with status ${tar_result}")
endif()
endif()
endfunction()
if (ENABLE_TIME_ZONE_DATABASE_DOWNLOAD)
remove_path_if_version_changed("${TZDB_VERSION}" "${TZDB_VERSION_FILE}" "${TZDB_PATH}")
if (NOT EXISTS "${TZDB_ZIP_PATH}")
message(STATUS "Downloading time zone database from ${TZDB_ZIP_URL}...")
file(DOWNLOAD "${TZDB_ZIP_URL}" "${TZDB_ZIP_PATH}" INACTIVITY_TIMEOUT 10)
endif()
extract_tzdb_file("${TZDB_AFRICA_SOURCE}" "${TZDB_AFRICA_PATH}")
extract_tzdb_file("${TZDB_ANTARCTICA_SOURCE}" "${TZDB_ANTARCTICA_PATH}")
extract_tzdb_file("${TZDB_ASIA_SOURCE}" "${TZDB_ASIA_PATH}")
extract_tzdb_file("${TZDB_AUSTRALASIA_SOURCE}" "${TZDB_AUSTRALASIA_PATH}")
extract_tzdb_file("${TZDB_ETCETERA_SOURCE}" "${TZDB_ETCETERA_PATH}")
extract_tzdb_file("${TZDB_EUROPE_SOURCE}" "${TZDB_EUROPE_PATH}")
extract_tzdb_file("${TZDB_NORTH_AMERICA_SOURCE}" "${TZDB_NORTH_AMERICA_PATH}")
extract_tzdb_file("${TZDB_SOUTH_AMERICA_SOURCE}" "${TZDB_SOUTH_AMERICA_PATH}")
set(TIME_ZONE_DATA_HEADER LibTimeZone/TimeZoneData.h)
set(TIME_ZONE_DATA_IMPLEMENTATION LibTimeZone/TimeZoneData.cpp)
set(TIME_ZONE_META_TARGET_PREFIX LibTimeZone_)
if (CMAKE_CURRENT_BINARY_DIR MATCHES ".*/LibTimeZone") # Serenity build.
set(TIME_ZONE_DATA_HEADER TimeZoneData.h)
set(TIME_ZONE_DATA_IMPLEMENTATION TimeZoneData.cpp)
set(TIME_ZONE_META_TARGET_PREFIX "")
endif()
invoke_generator(
"TimeZoneData"
Lagom::GenerateTimeZoneData
"${TZDB_VERSION_FILE}"
"${TIME_ZONE_META_TARGET_PREFIX}"
"${TIME_ZONE_DATA_HEADER}"
"${TIME_ZONE_DATA_IMPLEMENTATION}"
arguments "${TZDB_AFRICA_PATH}" "${TZDB_ANTARCTICA_PATH}" "${TZDB_ASIA_PATH}" "${TZDB_AUSTRALASIA_PATH}" "${TZDB_ETCETERA_PATH}" "${TZDB_EUROPE_PATH}" "${TZDB_NORTH_AMERICA_PATH}" "${TZDB_SOUTH_AMERICA_PATH}"
)
set(TIME_ZONE_DATA_SOURCES
${TIME_ZONE_DATA_HEADER}
${TIME_ZONE_DATA_IMPLEMENTATION}
)
endif()

View File

@ -216,6 +216,11 @@ function(lagom_test source)
)
endfunction()
if (NOT TARGET all_generated)
# Meta target to run all code-gen steps in the build.
add_custom_target(all_generated)
endif()
# AK/Core
# Note: AK is included in LagomCore for the host build instead of LibC per the target build
file(GLOB AK_SOURCES CONFIGURE_DEPENDS "../../AK/*.cpp")
@ -240,6 +245,19 @@ if (APPLE)
target_link_options(LagomMain PRIVATE -undefined dynamic_lookup)
endif()
# TimeZone
# This is needed even if Lagom is not enabled because it is depended upon by code generators.
if (NOT ENABLE_OSS_FUZZ AND NOT ENABLE_FUZZER_SANITIZER)
include(time_zone_data)
else()
set(ENABLE_TIME_ZONE_DATABASE_DOWNLOAD OFF)
endif()
file(GLOB LIBTIMEZONE_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibTimeZone/*.cpp")
lagom_lib(TimeZone timezone
SOURCES ${LIBTIMEZONE_SOURCES} ${TIME_ZONE_DATA_SOURCES}
)
target_compile_definitions(LagomTimeZone PRIVATE ENABLE_TIME_ZONE_DATA=$<BOOL:${ENABLE_TIME_ZONE_DATABASE_DOWNLOAD}>)
# Manually install AK headers
install(
DIRECTORY "${SERENITY_PROJECT_ROOT}/AK"
@ -255,12 +273,6 @@ if (NOT ENABLE_OSS_FUZZ AND NOT ENABLE_FUZZER_SANITIZER)
endif()
if (BUILD_LAGOM)
if (NOT TARGET all_generated)
# Meta target to run all code-gen steps in the build.
add_custom_target(all_generated)
endif()
# Lagom Libraries
# Archive

View File

@ -1,4 +1,5 @@
add_subdirectory(IPCCompiler)
add_subdirectory(LibTimeZone)
add_subdirectory(LibUnicode)
add_subdirectory(LibWeb)
add_subdirectory(StateMachineGenerator)

View File

@ -0,0 +1 @@
lagom_tool(GenerateTimeZoneData SOURCES GenerateTimeZoneData.cpp LIBS LagomMain)

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2022, Tim Flynn <trflynn89@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/SourceGenerator.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <AK/Vector.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/File.h>
static void generate_time_zone_data_header(Core::File& file)
{
StringBuilder builder;
SourceGenerator generator { builder };
generator.append(R"~~~(
#pragma once
)~~~");
VERIFY(file.write(generator.as_string_view()));
}
static void generate_time_zone_data_implementation(Core::File& file)
{
StringBuilder builder;
SourceGenerator generator { builder };
generator.append(R"~~~(
#include <LibTimeZone/TimeZoneData.h>
)~~~");
VERIFY(file.write(generator.as_string_view()));
}
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
StringView generated_header_path;
StringView generated_implementation_path;
Vector<StringView> time_zone_paths;
Core::ArgsParser args_parser;
args_parser.add_option(generated_header_path, "Path to the time zone data header file to generate", "generated-header-path", 'h', "generated-header-path");
args_parser.add_option(generated_implementation_path, "Path to the time zone data implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
args_parser.add_positional_argument(time_zone_paths, "Paths to the time zone database files", "time-zone-paths");
args_parser.parse(arguments);
auto open_file = [&](StringView path) -> ErrorOr<NonnullRefPtr<Core::File>> {
if (path.is_empty()) {
args_parser.print_usage(stderr, arguments.argv[0]);
return Error::from_string_literal("Must provide all command line options"sv);
}
return Core::File::open(path, Core::OpenMode::ReadWrite);
};
auto generated_header_file = TRY(open_file(generated_header_path));
auto generated_implementation_file = TRY(open_file(generated_implementation_path));
generate_time_zone_data_header(generated_header_file);
generate_time_zone_data_implementation(generated_implementation_file);
return 0;
}

View File

@ -46,6 +46,7 @@ add_subdirectory(LibSystem)
add_subdirectory(LibTest)
add_subdirectory(LibTextCodec)
add_subdirectory(LibThreading)
add_subdirectory(LibTimeZone)
add_subdirectory(LibTLS)
add_subdirectory(LibUnicode)
add_subdirectory(LibUSBDB)

View File

@ -0,0 +1,8 @@
include(${SerenityOS_SOURCE_DIR}/Meta/CMake/time_zone_data.cmake)
if (DEFINED TIME_ZONE_DATA_SOURCES)
set(SOURCES ${TIME_ZONE_DATA_SOURCES})
serenity_lib(LibTimeZoneData timezonedata)
target_compile_options(LibTimeZoneData PRIVATE -g0 -Os)
target_link_libraries(LibTimeZoneData LibCore)
endif()