diff --git a/generate4.xml b/generate4.xml
index 1e081cb2..5978ef99 100644
--- a/generate4.xml
+++ b/generate4.xml
@@ -22,6 +22,9 @@
+
+
+
@@ -40,7 +43,8 @@
-
+
+
@@ -864,12 +868,15 @@
-
+
+
+
+
@@ -941,9 +948,6 @@
-
-
-
@@ -954,12 +958,6 @@
-
-
-
-
-
-
diff --git a/lib/cmake-output.gsl b/lib/cmake-output.gsl
index aed7ef87..be9ed2c7 100644
--- a/lib/cmake-output.gsl
+++ b/lib/cmake-output.gsl
@@ -35,7 +35,7 @@
#------------------------------------------------------------------------------
.endmacro
.
-.macro emit_find_dependency(dependency, target, repository, host, function_name)
+.macro global.emit_find_dependency(dependency, target, repository, host, function_name)
. define my.dependency = emit_find_dependency.dependency
. define my.target = emit_find_dependency.target
. define my.repository = emit_find_dependency.repository
diff --git a/lib/filesystem.gsl b/lib/filesystem.gsl
index db71d84e..7d4355d5 100644
--- a/lib/filesystem.gsl
+++ b/lib/filesystem.gsl
@@ -18,21 +18,30 @@ gsl from "../library/string.gsl"
#------------------------------------------------------------------------------
# Path manipulation tools.
#------------------------------------------------------------------------------
-function path_append(basepath, baserelativepath)
- if (!is_empty(my.basepath))
- if (!ends_with(my.basepath, "/") & !ends_with(my.basepath, "\\"))
- return "$(my.basepath)/$(my.baserelativepath)"
- else
- return "$(my.basepath)$(my.baserelativepath)"
- endif
+function global.path_append(base_path, base_relative_path)
+ if is_empty(my.base_path)
+ return my.base_relative_path
+ endif
+
+ if !ends_with(my.base_path, "/") & !starts_with(my.base_relative_path, "/")
+ return "$(my.base_path)/$(my.base_relative_path)"
endif
- return "$(my.baserelativepath)"
+
+ return "$(my.base_path)$(my.base_relative_path)"
+endfunction
+
+function global.substitute_separator(path, prev, next)
+ define my.path = substitute_separator.path
+ define my.prev = substitute_separator.prev
+ define my.next = substitute_separator.next
+
+ return string.replace(my.path, '$(my.prev)|$(my.next)')
endfunction
#------------------------------------------------------------------------------
# I/O utilities.
#------------------------------------------------------------------------------
-function create_directory(path)
+function global.create_directory(path)
define my.result = directory.create(my.path)
if (my.result = 0)
return
@@ -40,6 +49,180 @@ function create_directory(path)
abort "Directory creation failure: $(error_text)"
endfunction
+function global.calculated_name(file, meta)
+ define my.file = calculated_name.file
+ define my.meta = calculated_name.meta
+
+ for my.meta.match as _match where ends_with(my.file.name, _match.suffix)
+ if defined(_match.strip)
+ return string.substr(my.file.name, 0, string.length(my.file.name) - string.length(_match.strip) - 1)
+ endif
+ endfor
+
+ return my.file.name
+endfunction
+
+function global.is_targeted_file(file, meta)
+ define my.file = is_targeted_file.file
+ define my.meta = is_targeted_file.meta
+
+ define my.filterless = (count(my.meta.match) = 0)
+
+ if my.filterless
+ return 1
+ endif
+
+ for my.meta.match as _filter where defined(_filter.suffix)
+ if ends_with(my.file.name, _filter.suffix)
+ return 1
+ endif
+ endfor
+
+ return 0
+endfunction
+
+function global.discover_files(files, meta, path, recurse)
+ define my.files = discover_files.files
+ define my.meta = discover_files.meta
+ define my.path = discover_files.path
+ define my.recurse = discover_files.recurse ? 1
+
+ # meta presumed structure:
+ #
+ #
+ #
+
+ define my.directory = directory.open(my.path)?
+
+ if !defined(my.directory)
+ abort "Directory open failure: $(error_text)"
+ endif
+
+ my.files.path = my.directory.path
+ my.files.name = my.directory.name
+ my.files.query = my.path
+
+ if my.recurse
+ for my.directory.directory as _subdirectory
+ new my.files.directory as _directory
+ discover_files(_directory, my.meta, "$(_subdirectory.path)$(_subdirectory.name)")
+ endnew
+ endfor
+ endif
+
+ for my.directory.file as _file by _file.name \
+ where is_targeted_file(_file, my.meta)
+
+ define my.modified_name = calculated_name(_file, my.meta)
+
+ #if !(my.modified_name = _file.name)
+ # check for redundancy, if so skip
+ if !(count(my.files.file, (count.name = my.modified_name)) = 0)
+ next
+ endif
+ #endif
+
+ new my.files.file as _active_file
+ _active_file.name = my.modified_name
+ _active_file.path = _file.path
+ endnew
+ endfor
+endfunction
+
+function global.matches_filters(filters, filename)
+ define my.filters = matches_filters.filters
+ define my.filename = matches_filters.filename
+
+ if count(my.filters.match) = 0
+ return 1
+ endif
+
+ for my.filters.match as _match
+ if ends_with(my.filename, _match.suffix)
+ return 1
+ endif
+ endfor
+
+ return 0
+endfunction
+
+function global.populate_files_from_path(path_substitutions, files, filters, files_path, absolute_path_base, intended_prefix_base)
+ define my.path_substitutions = populate_files_from_path.path_substitutions
+ define my.files = populate_files_from_path.files
+ define my.filters = populate_files_from_path.filters
+ define my.files_path = populate_files_from_path.files_path
+ define my.absolute_path_base = populate_files_from_path.absolute_path_base
+ define my.intended_prefix_base = populate_files_from_path.intended_prefix_base
+
+ define my.path = path_append(my.absolute_path_base, my.files_path.path)
+ define my.recurse = is_defined_positive(my.files_path, "recursive")
+
+ new my.files.directory as _directory
+ discover_files(_directory, my.filters, my.path, my.recurse)
+ endnew
+
+ new my.path_substitutions.substitution as _sub
+ _sub.absolute_path = my.path
+ _sub.relative_path_prefix = path_append(my.intended_prefix_base, \
+ my.files_path.path)
+
+ _sub.unprefixed_path = my.files_path.path
+
+ if defined(my.files_path->msbuild) & defined(my.files_path->msbuild.filter)
+ _sub.filter = my.files_path->msbuild.filter
+ else
+ _sub.filter = my.files_path.path
+ endif
+
+ #echo("sub absolute_path | $(_sub.absolute_path)")
+ #echo("sub relative_path_prefix | $(_sub.relative_path_prefix)")
+ #echo("sub unprefixed_path | $(_sub.unprefixed_path)")
+ #echo("sub filter | $(_sub.filter)")
+ endnew
+ endfunction
+
+function global.populate_files(path_substitutions, files, filters, target, absolute_path_base, intended_prefix_base)
+ define my.path_substitutions = populate_files.path_substitutions
+ define my.files = populate_files.files
+ define my.filters = populate_files.filters
+ define my.target = populate_files.target
+ define my.absolute_path_base = populate_files.absolute_path_base
+ define my.intended_prefix_base = populate_files.intended_prefix_base
+
+ for my.target.headers as _file_path where is_defined_positive(_file_path, "root")
+ populate_files_from_path(my.path_substitutions, my.files, my.filters, \
+ _file_path, my.absolute_path_base, my.intended_prefix_base)
+ endfor
+
+ for my.target.sources as _file_path
+ populate_files_from_path(my.path_substitutions, my.files, my.filters, \
+ _file_path, my.absolute_path_base, my.intended_prefix_base)
+ endfor
+
+ for my.target.resources as _file_path
+ populate_files_from_path(my.path_substitutions, my.files, my.filters, \
+ _file_path, my.absolute_path_base, my.intended_prefix_base)
+ endfor
+
+ # substitution of last resort
+ new my.path_substitutions.substitution as _sub
+ _sub.absolute_path = my.absolute_path_base
+ _sub.relative_path_prefix = my.intended_prefix_base
+ endnew
+endfunction
+
+function repository_absolute_path(repository, configuration)
+ define my.repository = repository_absolute_path.repository
+ define my.configuration = repository_absolute_path.configuration
+
+ define my.path = path_append(my.configuration->templates.src_root_path, \
+ my.repository.name)
+
+ define my.directory = directory.open(my.path)
+
+ return my.directory.path
+endfunction
+
.endtemplate
.template 1
.
diff --git a/lib/msbuild.gsl b/lib/msbuild.gsl
new file mode 100644
index 00000000..b22d43c2
--- /dev/null
+++ b/lib/msbuild.gsl
@@ -0,0 +1,59 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL libbitcoin msbuild utilities in the 'global' scope.
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+###############################################################################
+# Functions
+###############################################################################
+
+###############################################################################
+# Specific pattern xml functions
+###############################################################################
+function global.target_name(target)
+ define my.target = target_name.target
+
+ if defined(my.target.msvcproj)
+ return my.target.msvcproj
+ endif
+
+ return my.target.name
+endfunction
+
+function global.path(input)
+ return string.replace(path.input, "/|\\")
+endfunction
+
+function global.project_relative_path(target, meta, tooling)
+ define my.target = project_relative_path.target
+ define my.meta = project_relative_path.meta
+ define my.tooling = project_relative_path.tooling
+
+ define my.relevant = target_name(my.target)
+ define my.path = path_append(my.relevant, "$(my.relevant).vcxproj")
+
+ if defined(my.tooling.relative_path)
+ my.path = path_append(my.tooling.relative_path, my.path)
+ endif
+
+ if defined(my.meta.relative_path)
+ my.path = path_append(my.meta.relative_path, my.path)
+ endif
+
+ return my.path
+endfunction
+
+.endtemplate
+.template 1
+.
+.##############################################################################
+.# Macros
+.##############################################################################
+.
+.endtemplate
+
diff --git a/lib/uuid.gsl b/lib/uuid.gsl
new file mode 100644
index 00000000..a00fba67
--- /dev/null
+++ b/lib/uuid.gsl
@@ -0,0 +1,78 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL libbitcoin uuid utilities in the 'global' scope.
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+###############################################################################
+# Functions
+###############################################################################
+function global.uuid_initialize()
+ return 0
+endfunction
+
+function global.uuid_inc(uuid)
+ return uuid_inc.uuid + 1
+endfunction
+
+function global.to_hex(value)
+ define my.hex_value = math.mod(to_hex.value, 16)
+
+ if (my.hex_value >= 0 & my.hex_value <= 9)
+ return conv.string(my.hex_value)
+ elsif (my.hex_value = 10)
+ return "a"
+ elsif (my.hex_value = 11)
+ return "b"
+ elsif (my.hex_value = 12)
+ return "c"
+ elsif (my.hex_value = 13)
+ return "d"
+ elsif (my.hex_value = 14)
+ return "e"
+ elsif (my.hex_value = 15)
+ return "f"
+ else
+ abort("Value '$(my.hex_value)' outside hex range.")
+ endif
+endfunction
+
+function to_uuid(seed, value)
+ define my.seed = to_uuid.seed
+ define my.value = to_uuid.value
+ define my.wip = "0"
+
+ while (my.value > 0)
+ my.wip += to_hex(my.value)
+ my.value = math.floor(my.value / 16)
+ endwhile
+
+ # NOTE should vary this?
+ define my.uuid = left(my.seed, 19)
+ my.uuid += "0000-"
+ define my.iter = 0
+
+ # NOTE supports at most 0x0fffffffffff
+ while ((my.iter + string.length(my.wip)) < 12)
+ my.uuid += 0
+ my.iter += 1
+ endwhile
+
+ my.uuid += my.wip
+
+ return my.uuid
+endfunction
+
+.endtemplate
+.template 1
+.
+.##############################################################################
+.# Macros
+.##############################################################################
+.
+.endtemplate
+
diff --git a/lib/xml-output.gsl b/lib/xml-output.gsl
new file mode 100644
index 00000000..06de5853
--- /dev/null
+++ b/lib/xml-output.gsl
@@ -0,0 +1,31 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL libbitcoin xml output utilities in the 'global' scope.
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+###############################################################################
+# Functions
+###############################################################################
+.endtemplate
+.template 1
+.
+.##############################################################################
+.# Macros
+.##############################################################################
+.
+.macro global.copyleft(name)
+
+.endmacro
+.
+.endtemplate
+
diff --git a/lib/xml.gsl b/lib/xml.gsl
index 09663700..0bed657b 100644
--- a/lib/xml.gsl
+++ b/lib/xml.gsl
@@ -39,6 +39,16 @@ function global.is_defined_positive(node, attribute)
((my.node.$(my.attribute) = "true") | (my.node.$(my.attribute) = "yes"))
endfunction
+function global.merge_child(destination, element, identifier)
+ define my.destination = merge_child.destination
+ define my.element = merge_child.element
+ define my.identifier = merge_child.identifier
+
+ if (count(my.destination.$(name(my.element)), count.$(my.identifier) = my.element.$(my.identifier)) = 0)
+ copy my.element to my.destination
+ endif
+endfunction
+
function global.merge_children_select(destination, source, name, identifier)
define my.destination = merge_children_select.destination
define my.source = merge_children_select.source
@@ -46,29 +56,39 @@ function global.merge_children_select(destination, source, name, identifier)
define my.identifier = merge_children_select.identifier
for my.source.$(my.name) as _child
- if (count(my.destination->$(my.name), $(my.name).$(identifier) = _child.$(identifier)) = 0)
- copy _child to my.destination
- endif
+ merge_child(my.destination, _child, my.identifier)
endfor
endfunction
-function global.canonicalize(result, host, canonical, name, identifier)
+function global.canonicalize_element(result, element, registrar, identifier)
+ define my.result = canonicalize_element.result
+ define my.element = canonicalize_element.element
+ define my.registrar = canonicalize_element.registrar
+ define my.identifier = canonicalize_element.identifier
+
+ if !defined(my.element.$(my.identifier))
+ copy my.element to my.result
+ elsif (count(my.result.$(name(my.element)), defined(this.$(my.identifier)) &\
+ (this.$(my.identifier) = my.element.$(my.identifier)), this) = 0)
+
+ if (count(my.registrar.$(name(my.element)),\
+ this.$(my.identifier) = my.element.$(my.identifier), this) > 0)
+ copy my.registrar->$(name(my.element))(.$(my.identifier) = my.element.$(my.identifier)) to my.result
+ else
+ copy my.element to my.result
+ endif
+ endif
+endfunction
+
+function global.canonicalize(result, host, registrar, name, identifier)
define my.result = canonicalize.result
define my.host = canonicalize.host
- define my.canonical = canonicalize.canonical
+ define my.registrar = canonicalize.registrar
define my.name = canonicalize.name
define my.identifier = canonicalize.identifier
for my.host.$(my.name) as _element
- if (!defined(_element.$(my.identifier)))
- copy _element to my.result
- elsif (count(my.result.$(my.name), defined(this.$(my.identifier)) & (this.$(my.identifier) = _element.$(my.identifier)), this) = 0)
- if (count(my.canonical.$(my.name), .$(my.identifier) = _element.$(my.identifier)) > 0)
- copy my.canonical->$(my.name)(.$(my.identifier) = _element.$(my.identifier)) to my.result
- else
- copy _element to my.result
- endif
- endif
+ canonicalize_element(my.result, _element, my.registrar, my.identifier)
endfor
endfunction
@@ -188,7 +208,30 @@ function global.get_option(reference, target, repository)
return my.result
endfunction
-function canonical_dependency_list(result, repository, configuration)
+function global.target_dependency_list(result, target, repository, configuration)
+ define my.result = target_dependency_list.result
+ define my.target = target_dependency_list.target
+ define my.repository = target_dependency_list.repository
+ define my.configuration = target_dependency_list.configuration
+
+ define my.registrar = my.configuration->registrar(id = "dependency")
+
+ for my.target.dependency as _dep
+ if (count_matches_name(my.configuration, "repository", _dep.name) > 0)
+ define my.dep_repository = my.configuration->repository(name = _dep.name)
+ define my.dep_target = my.dep_repository->library(name = _dep.name)
+
+ target_dependency_list(my.result, my.dep_target, \
+ my.dep_repository, my.configuration)
+ else
+ canonicalize_element(my.result, _dep, my.registrar, "name")
+ endif
+
+ merge_components(my.result, _dep)
+ endfor
+endfunction
+
+function global.canonical_dependency_list(result, repository, configuration)
define my.result = canonical_dependency_list.result
define my.repository = canonical_dependency_list.repository
define my.configuration = canonical_dependency_list.configuration
@@ -212,7 +255,7 @@ function canonical_dependency_list(result, repository, configuration)
endfor
endfunction
-function calculate_presets(result, configuration, repository)
+function global.calculate_presets(result, configuration, repository)
define my.result = calculate_presets.result
define my.configuration = calculate_presets.configuration
define my.repository = calculate_presets.repository
@@ -260,6 +303,13 @@ function calculate_presets(result, configuration, repository)
# endfor
endfunction
+function global.is_target_element(element)
+ define my.element = is_target_element.element
+ return (name(my.element) = "library") \
+ | (name(my.element) = "test") \
+ | (name(my.element) = "binary")
+endfunction
+
.endtemplate
.template 1
.
diff --git a/props/version4/project/libbitcoin-database/libbitcoin-database-test/libbitcoin-database-test.props b/props/version4/project/libbitcoin-database/libbitcoin-database-test/libbitcoin-database-test.props
index 8f9501d9..24a00872 100644
--- a/props/version4/project/libbitcoin-database/libbitcoin-database-test/libbitcoin-database-test.props
+++ b/props/version4/project/libbitcoin-database/libbitcoin-database-test/libbitcoin-database-test.props
@@ -50,6 +50,7 @@
+
diff --git a/props/version4/project/libbitcoin-database/libbitcoin-database-tools/libbitcoin-database-tools.props b/props/version4/project/libbitcoin-database/libbitcoin-database-tools/libbitcoin-database-tools.props
index b12204c9..e96ef6e2 100644
--- a/props/version4/project/libbitcoin-database/libbitcoin-database-tools/libbitcoin-database-tools.props
+++ b/props/version4/project/libbitcoin-database/libbitcoin-database-tools/libbitcoin-database-tools.props
@@ -47,6 +47,7 @@
+
diff --git a/props/version4/project/libbitcoin-database/libbitcoin-database/libbitcoin-database.props b/props/version4/project/libbitcoin-database/libbitcoin-database/libbitcoin-database.props
index 7c0796e4..411f4de3 100644
--- a/props/version4/project/libbitcoin-database/libbitcoin-database/libbitcoin-database.props
+++ b/props/version4/project/libbitcoin-database/libbitcoin-database/libbitcoin-database.props
@@ -46,6 +46,7 @@
+
diff --git a/props/version4/project/libbitcoin-network/libbitcoin-network-test/libbitcoin-network-test.props b/props/version4/project/libbitcoin-network/libbitcoin-network-test/libbitcoin-network-test.props
index 4ce82f2b..875a033a 100644
--- a/props/version4/project/libbitcoin-network/libbitcoin-network-test/libbitcoin-network-test.props
+++ b/props/version4/project/libbitcoin-network/libbitcoin-network-test/libbitcoin-network-test.props
@@ -61,6 +61,7 @@
+
diff --git a/props/version4/project/libbitcoin-network/libbitcoin-network/libbitcoin-network.props b/props/version4/project/libbitcoin-network/libbitcoin-network/libbitcoin-network.props
index 79d0ec24..8b805b9d 100644
--- a/props/version4/project/libbitcoin-network/libbitcoin-network/libbitcoin-network.props
+++ b/props/version4/project/libbitcoin-network/libbitcoin-network/libbitcoin-network.props
@@ -84,6 +84,7 @@
+
diff --git a/props/version4/project/libbitcoin-node/bn/bn.props b/props/version4/project/libbitcoin-node/bn/bn.props
index db7ebe48..9448b880 100644
--- a/props/version4/project/libbitcoin-node/bn/bn.props
+++ b/props/version4/project/libbitcoin-node/bn/bn.props
@@ -55,6 +55,7 @@
+
diff --git a/props/version4/project/libbitcoin-node/libbitcoin-node-test/libbitcoin-node-test.props b/props/version4/project/libbitcoin-node/libbitcoin-node-test/libbitcoin-node-test.props
index 3b92d0f5..f488377c 100644
--- a/props/version4/project/libbitcoin-node/libbitcoin-node-test/libbitcoin-node-test.props
+++ b/props/version4/project/libbitcoin-node/libbitcoin-node-test/libbitcoin-node-test.props
@@ -57,6 +57,7 @@
+
diff --git a/props/version4/project/libbitcoin-node/libbitcoin-node/libbitcoin-node.props b/props/version4/project/libbitcoin-node/libbitcoin-node/libbitcoin-node.props
index 100424c8..6214b253 100644
--- a/props/version4/project/libbitcoin-node/libbitcoin-node/libbitcoin-node.props
+++ b/props/version4/project/libbitcoin-node/libbitcoin-node/libbitcoin-node.props
@@ -59,6 +59,7 @@
+
diff --git a/props/version4/project/libbitcoin-server/bs/bs.props b/props/version4/project/libbitcoin-server/bs/bs.props
index 5d4d73c3..ba867487 100644
--- a/props/version4/project/libbitcoin-server/bs/bs.props
+++ b/props/version4/project/libbitcoin-server/bs/bs.props
@@ -59,6 +59,7 @@
+
diff --git a/props/version4/project/libbitcoin-server/libbitcoin-server-test/libbitcoin-server-test.props b/props/version4/project/libbitcoin-server/libbitcoin-server-test/libbitcoin-server-test.props
index accd225f..895afc7b 100644
--- a/props/version4/project/libbitcoin-server/libbitcoin-server-test/libbitcoin-server-test.props
+++ b/props/version4/project/libbitcoin-server/libbitcoin-server-test/libbitcoin-server-test.props
@@ -61,6 +61,7 @@
+
diff --git a/props/version4/project/libbitcoin-server/libbitcoin-server/libbitcoin-server.props b/props/version4/project/libbitcoin-server/libbitcoin-server/libbitcoin-server.props
index 6727044f..d2794640 100644
--- a/props/version4/project/libbitcoin-server/libbitcoin-server/libbitcoin-server.props
+++ b/props/version4/project/libbitcoin-server/libbitcoin-server/libbitcoin-server.props
@@ -63,6 +63,7 @@
+
diff --git a/props/version4/project/libbitcoin-system/libbitcoin-system-examples/libbitcoin-system-examples.props b/props/version4/project/libbitcoin-system/libbitcoin-system-examples/libbitcoin-system-examples.props
index 02df845d..5847fe7d 100644
--- a/props/version4/project/libbitcoin-system/libbitcoin-system-examples/libbitcoin-system-examples.props
+++ b/props/version4/project/libbitcoin-system/libbitcoin-system-examples/libbitcoin-system-examples.props
@@ -43,6 +43,7 @@
+
diff --git a/props/version4/project/libbitcoin-system/libbitcoin-system-test/libbitcoin-system-test.props b/props/version4/project/libbitcoin-system/libbitcoin-system-test/libbitcoin-system-test.props
index 135a0252..4de11796 100644
--- a/props/version4/project/libbitcoin-system/libbitcoin-system-test/libbitcoin-system-test.props
+++ b/props/version4/project/libbitcoin-system/libbitcoin-system-test/libbitcoin-system-test.props
@@ -54,6 +54,7 @@
+
diff --git a/props/version4/project/libbitcoin-system/libbitcoin-system/libbitcoin-system.props b/props/version4/project/libbitcoin-system/libbitcoin-system/libbitcoin-system.props
index 310b4f60..5d6f09fd 100644
--- a/props/version4/project/libbitcoin-system/libbitcoin-system/libbitcoin-system.props
+++ b/props/version4/project/libbitcoin-system/libbitcoin-system/libbitcoin-system.props
@@ -83,6 +83,7 @@
+
diff --git a/templates/cmake/CMakeLists.txt.gsl b/templates/cmake/CMakeLists.txt.gsl
index 70e5d222..3f6bfa01 100644
--- a/templates/cmake/CMakeLists.txt.gsl
+++ b/templates/cmake/CMakeLists.txt.gsl
@@ -37,7 +37,6 @@ function generate_CMakeLists(configuration)
require(my.template->cmake, "cmake", "rootpath")
define my.project_path_suffix = my.template.outpath
- define my.root_path = my.template->cmake.rootpath
for my.configuration.repository by .name as _repository
require(_repository, "repository", "name")
@@ -52,7 +51,7 @@ function generate_CMakeLists(configuration)
notify(my.out_file)
output(my.out_file)
- emit_CMakeLists(_repository, my.root_path)
+ emit_CMakeLists(_repository, my.configuration, my.template)
close
endfor _repository
@@ -478,15 +477,68 @@ endfunction
.endtemplate
.template 1
.
-.macro emit_CMakeLists(repository, root_path)
+.macro emit_CMakeLists(repository, configuration, meta)
. define my.repository = emit_CMakeLists.repository
-. define my.root_path = emit_CMakeLists.root_path
+. define my.configuration = emit_CMakeLists.configuration
+. define my.meta = emit_CMakeLists.meta
+.
+. define my.github = my.configuration->registrar(.id = "dependency")\
+ ->dependency(.name = my.repository.name)->github
.
. copyleft(my.repository.name)
cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
+find_package(Git QUIET)
+
+set( GIT_COMMIT_HASH "unknown" )
+set( GIT_COMMIT_HEIGHT 0 )
+set( GIT_DIRTY 0 )
+set( GIT_ORIGIN_URL "https://github.com/$(my.github.owner)/$(my.repository.name)" )
+
+if ( GIT_EXECUTABLE )
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_COMMIT_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET )
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_COMMIT_HEIGHT
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET )
+
+ if ( NOT GIT_COMMIT_HEIGHT )
+ set( GIT_COMMIT_HEIGHT 0 )
+ endif()
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} remote get-url origin
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_ORIGIN_URL
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET )
+
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} status --porcelain
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_STATUS
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET )
+
+ if ( GIT_STATUS )
+ set( GIT_DIRTY 1 )
+ endif()
+endif()
+
+set( LIBBITCOIN_VERSION_MAJOR $(my.repository->version.major) )
+set( LIBBITCOIN_VERSION_MINOR $(my.repository->version.minor) )
+set( LIBBITCOIN_VERSION_PATCH ${GIT_COMMIT_HEIGHT} )
+
project( $(my.repository.name)
- VERSION $(my.repository.version)
+ VERSION ${LIBBITCOIN_VERSION_MAJOR}.${LIBBITCOIN_VERSION_MINOR}.${LIBBITCOIN_VERSION_PATCH}
DESCRIPTION "$(my.repository.description)"
LANGUAGES $(language_list(my.repository)) )
@@ -512,52 +564,55 @@ endif()
. heading("Linker options.")
. render_link_option_checks(my.repository)
+
+. heading("Configurable file(s).")
+. render_configurable_files(my.repository, my.meta)
.
. for my.repository.library as _library
. heading("$(target_name(_library)) library")
-. emit_target(_library, my.repository, my.root_path)
+. emit_target(_library, my.repository, my.meta)
.
. endfor
.
. for my.repository.test as _test
. heading("$(target_name(_test)) tests")
-. emit_target(_test, my.repository, my.root_path)
+. emit_target(_test, my.repository, my.meta)
. endfor
.
. for my.repository.binary as _binary
. heading("$(target_name(_binary)) executable")
-. emit_target(_binary, my.repository, my.root_path)
+. emit_target(_binary, my.repository, my.meta)
. endfor
.
. heading("Installation routine.")
-. emit_installation(my.repository, my.root_path)
+. emit_installation(my.repository, my.meta)
.
.endmacro # emit_CMakeLists
.
-.macro emit_installation(repository, root_path)
+.macro emit_installation(repository, meta)
. define my.repository = emit_installation.repository
-. define my.root_path = emit_installation.root_path
+. define my.meta = emit_installation.meta
.
include( GNUInstallDirs )
include( CMakePackageConfigHelpers )
. for my.repository.library as _target
-. emit_install_target(_target, my.repository, my.root_path)
+. emit_install_target(_target, my.repository, my.meta)
. endfor
.
. for my.repository.binary as _target where is_defined_positive(_target, "install")
-. emit_install_target(_target, my.repository, my.root_path)
+. emit_install_target(_target, my.repository, my.meta)
. endfor
.
.endmacro # emit_installation
.
-.macro emit_install_target(target, repository, root_path)
+.macro emit_install_target(target, repository, meta)
. define my.target = emit_install_target.target
. define my.repository = emit_install_target.repository
-. define my.root_path = emit_install_target.root_path
+. define my.meta = emit_install_target.meta
.
. define my.indent = defined(my.target.option) ?? " " ? ""
.
@@ -609,6 +664,37 @@ endif()
.
.endmacro # emit_install_target
.
+.macro render_configurable_files(repository, meta)
+. define my.repository = render_configurable_files.repository
+. define my.meta = render_configurable_files.meta
+.
+. for my.repository.library as _library
+. for _library.configurable as _configurable
+. emit_configure_file(_configurable, my.meta)
+. endfor
+. endfor
+. for my.repository.test as _test
+. for _test.configurable as _configurable
+. emit_configure_file(_configurable, my.meta)
+. endfor
+. endfor
+. for my.repository.binary as _binary
+. for _binary.configurable as _configurable
+. emit_configure_file(_configurable, my.meta)
+. endfor
+. endfor
+.endmacro # render_configurable_files
+.
+.macro emit_configure_file(configurable, meta)
+. define my.config = emit_configure_file.configurable
+. define my.meta = emit_configure_file.meta
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/$(my.meta->cmake.rootpath)/$(my.config.path)/$(my.config.input)
+ ${CMAKE_CURRENT_BINARY_DIR}/$(my.config.path)/$(my.config.output)
+ @ONLY )
+.endmacro # emit_configure_files
+.
.macro emit_list_dependency(dependency, target, repository, indent)
. define my.dependency = emit_list_dependency.dependency
. define my.target = emit_list_dependency.target
@@ -702,10 +788,10 @@ $(my.indent))
.
.endmacro # emit_add_test
.
-.macro emit_target(target, repository, root_path)
+.macro emit_target(target, repository, meta)
. define my.target = emit_target.target
. define my.repository = emit_target.repository
-. define my.root_path = emit_target.root_path
+. define my.meta = emit_target.meta
. define my.indent = defined(my.target.option) ?? " " ? ""
.
. if (defined(my.target.option))
@@ -734,9 +820,9 @@ $(my.indent)add_executable( $(target_name(my.target)) )
. emit_target_compile_assignment("target_link_options", "link", \
my.target, my.repository, my.indent)
.
-. emit_target_files(my.target, my.repository, my.root_path, my.indent)
+. emit_target_files(my.target, my.repository, my.meta, my.indent)
.
-. emit_target_include_directories(my.target, my.repository, my.root_path, my.indent)
+. emit_target_include_directories(my.target, my.repository, my.meta, my.indent)
.
. emit_target_link_libraries(my.target, my.repository, my.indent)
.
@@ -766,10 +852,10 @@ endif()
. endif
.endmacro # emit_target
.
-.macro emit_target_include_directories(target, repository, root_path, indent)
+.macro emit_target_include_directories(target, repository, meta, indent)
. define my.target = emit_target_include_directories.target
. define my.repository = emit_target_include_directories.repository
-. define my.root_path = emit_target_include_directories.root_path
+. define my.meta = emit_target_include_directories.meta
. define my.indent = emit_target_include_directories.indent
. define my.indent_item = " $(my.indent)"
.
@@ -780,20 +866,20 @@ endif()
$(my.indent)target_include_directories( $(target_name(my.target))
$(my.indent)$((name(my.target) = "library")?? "PUBLIC" ? "PRIVATE")
. for my.target.headers as _headers where is_defined_positive(_headers, "root")
-. emit_target_path(_headers, my.target, my.repository, my.indent_item, my.root_path)
+. emit_target_path(_headers, my.target, my.repository, my.indent_item, my.meta)
. for _headers.headers as _optional where is_defined_positive(_optional, "root")
-. emit_target_path(_optional, my.target, my.repository, my.indent_item, my.root_path)
+. emit_target_path(_optional, my.target, my.repository, my.indent_item, my.meta)
. endfor
. endfor
$(my.indent))
.endmacro # emit_target_include_directories
.
-.macro emit_target_path(pathholder, target, repository, indent, root_path)
+.macro emit_target_path(pathholder, target, repository, indent, meta)
. define my.pathholder = emit_target_path.pathholder
. define my.target = emit_target_path.target
. define my.repository = emit_target_path.repository
. define my.indent = emit_target_path.indent
-. define my.root_path = emit_target_path.root_path
+. define my.meta = emit_target_path.meta
.
. define my.prefix = ""
. define my.suffix = ""
@@ -808,7 +894,7 @@ $(my.indent))
. if !is_empty(my.prefix)
$(my.indent)$(my.prefix)
. endif
-$(my.indent_content)$
+$(my.indent_content)$cmake.rootpath)/$(my.pathholder.path)>
. if (target_installable(my.target))
$(my.indent_content)$
. endif
@@ -1023,10 +1109,10 @@ $(my.indent)if ( !HAS_FLAG_$(flag_name(my.flag):upper) )
$(my.indent)endif()
.endmacro # emit_check_compiler_flag
.
-.macro emit_target_files(target, repository, root_path, indent)
+.macro emit_target_files(target, repository, meta, indent)
. define my.target = emit_target_files.target
. define my.repository = emit_target_files.repository
-. define my.root_path = emit_target_files.root_path
+. define my.meta = emit_target_files.meta
. define my.indent = emit_target_files.indent
. define my.indent_headers = " $(my.indent)"
. define my.indent_sources = " $(my.indent)"
@@ -1042,31 +1128,35 @@ $(my.indent)endif()
. endif
.
. if (has_headers)
-. emit_files_declaration(my.target->headers, my.target, my.repository, my.root_path, my.indent)
+. emit_files_declaration(my.target->headers, my.target, my.repository, my.meta, my.indent)
. for my.target->headers.headers as _optional
-. emit_files_declaration(_optional, my.target, my.repository, my.root_path, my.indent)
+. emit_files_declaration(_optional, my.target, my.repository, my.meta, my.indent)
. endfor
. endif
.
. if (has_sources)
-. emit_files_declaration(my.target->sources, my.target, my.repository, my.root_path, my.indent)
+. emit_files_declaration(my.target->sources, my.target, my.repository, my.meta, my.indent)
. for my.target->sources.sources as _optional
-. emit_files_declaration(_optional, my.target, my.repository, my.root_path, my.indent)
+. emit_files_declaration(_optional, my.target, my.repository, my.meta, my.indent)
. endfor
. endif
$(my.indent)target_sources( $(my.target.name)
. if has_headers
-. if is_defined_positive(my.target->headers, "private")
- $(my.indent)PRIVATE
- $(my.indent)FILE_SET HEADERS
-. else
- $(my.indent)PUBLIC
+. define my.mode = is_defined_positive(my.target->headers, "private") ??\
+ "PRIVATE" ? "PUBLIC"
+.
+ $(my.indent)$(my.mode:upper)
$(my.indent)FILE_SET HEADERS
-. endif
- $(my.indent)BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/$(my.root_path)/$(my.target->headers.path)"
+ $(my.indent)BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/$(my.meta->cmake.rootpath)/$(my.target->headers.path)"
$(my.indent)FILES
. emit_target_sources_entry(my.target->headers, my.target, my.repository, my.indent_headers)
+. if (count(my.target.configurable, count.type = "headers") > 0)
+ $(my.indent)FILE_SET HEADERS
+ $(my.indent)BASE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/$(my.target->headers.path)"
+ $(my.indent)FILES
+. emit_target_configured_files("headers", my.target, my.repository, my.meta, " $(my.indent)")
+. endif
.
.# for my.target->headers.headers as _optional
.# emit_target_sources_entry(_optional, my.target, my.repository, my.indent_headers)
@@ -1083,11 +1173,23 @@ $(my.indent)target_sources( $(my.target.name)
$(my.indent))
.endmacro # emit_target_files
.
-.macro emit_files_declaration(item, target, repository, root_path, indent)
+.macro emit_target_configured_files(type, target, repository, meta, indent)
+. define my.type = emit_target_configured_files.type
+. define my.target = emit_target_configured_files.target
+. define my.repository = emit_target_configured_files.repository
+. define my.meta = emit_target_configured_files.meta
+. define my.indent = emit_target_configured_files.indent
+.
+. for my.target.configurable as _config where _config.type = my.type
+$(my.indent)"${CMAKE_CURRENT_BINARY_DIR}/$(_config.path)/$(_config.output)"
+. endfor
+.endmacro # emit_target_configured_files
+.
+.macro emit_files_declaration(item, target, repository, meta, indent)
. define my.item = emit_files_declaration.item
. define my.target = emit_files_declaration.target
. define my.repository = emit_files_declaration.repository
-. define my.root_path = emit_files_declaration.root_path
+. define my.meta = emit_files_declaration.meta
. define my.indent = emit_files_declaration.indent
.
. new languages as _languages
@@ -1101,7 +1203,7 @@ $(my.indent))
$(my.indent)file( GLOB_RECURSE $(my.target.name:c)_$(name(my.item):upper)$(my.suffix) CONFIGURE_DEPENDS
. for _languages.language as _lang
. for _lang.$(name(my.item)) as _entry where defined(_entry.suffix)
- $(my.indent)"${CMAKE_CURRENT_SOURCE_DIR}/$(my.root_path)/$(my.item.path)/*.$(_entry.suffix)"
+ $(my.indent)"${CMAKE_CURRENT_SOURCE_DIR}/$(my.meta->cmake.rootpath)/$(my.item.path)/*.$(_entry.suffix)"
. endfor
. endfor
$(my.indent))
diff --git a/templates/gsl.sln b/templates/gsl.sln
deleted file mode 100644
index 34231996..00000000
--- a/templates/gsl.sln
+++ /dev/null
@@ -1,226 +0,0 @@
-.template 0
-###############################################################################
-# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
-#
-# GSL generate libbitcoin .sln.
-#
-# This is a code generator built using the iMatix GSL code generation
-# language. See https://github.com/imatix/gsl for details.
-###############################################################################
-# Functions
-###############################################################################
-
-###
-### sln related string generators
-###
-function solution_relative_path(repository, path_prefix, vs_version)
- define my.repository = solution_relative_path.repository
- require(my.repository, "repository", "name")
- define my.subpath = "builds/msvc/$(my.vs_version)"
- return append_path(append_path(my.path_prefix,\
- canonical_path_name(my.repository)), my.subpath)
-endfunction
-
-function solution_file(repository, path_prefix, vs_version)
- define my.repository = solution_file.repository
- require(my.repository, "repository", "name")
- define my.relative_path = solution_relative_path(my.repository,\
- my.path_prefix, my.vs_version)
-
- return append_path(my.relative_path, "$(my.repository.name).sln")
-endfunction
-
-###
-### functional artifact emission
-###
-function emit_projects(repository)
- define my.repository = emit_projects.repository
- require(my.repository, "repository", "name")
-
- for my.repository->make.product as _product where has_uuid(_product)
-
- define my.project_name = project_name(_product, my.repository)
- define my.project_path = "$(my.project_name)\\$(my.project_name).vcxproj"
-
- emit_project(my.project_name, my.project_path, _product.uuid)
- endfor
-endfunction
-
-function emit_postsolution(repository)
- define my.repository = emit_postsolution.repository
- require(my.repository, "repository", "name")
-
- emit_global_postsolution_open()
-
- for my.repository->make.product as _product where has_uuid(_product)
- define my.project_name = project_name(_product, my.repository)
- define my.project_path = "$(my.project_name)\\$(my.project_name).vcxproj"
-
- if (is_program(_product))
- emit_binary_crossproduct(_product.uuid)
- elsif (is_library(_product))
- emit_library_crossproduct(_product.uuid)
- else
- abort("Unrecognized product type.")
- endif
- endfor
-
- emit_global_postsolution_close()
-endfunction
-
-function emit_solution(toolset, repository)
- define my.toolset = emit_solution.toolset
- define my.repository = emit_solution.repository
- require(my.repository, "repository", "name")
-
- emit_version(my.toolset)
- emit_projects(my.repository)
- emit_global_open()
- emit_presolution()
- emit_postsolution(my.repository)
- emit_solution_properties()
- emit_global_close()
-endfunction emit_solution
-
-###############################################################################
-# Macros
-###############################################################################
-.endtemplate
-.template 1
-.
-.macro emit_version(toolset)
-. define my.toolset = emit_version.toolset
-
-Microsoft Visual Studio Solution File, Format Version $(my.toolset->solution.format)
-# Visual Studio $(my.toolset->solution.year)
-VisualStudioVersion = $(my.toolset->solution->version.value)
-MinimumVisualStudioVersion = $(my.toolset->solution->version.min)
-.endmacro emit_version
-.
-.macro emit_project(project_name, project_path, uuid)
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$(my.project_name)", "$(my.project_path)", "{$(my.uuid:upper)}"
-EndProject
-.endmacro emit_project
-.
-.macro emit_global_open()
-Global
-.endmacro emit_global_open
-.
-.macro emit_global_close()
-EndGlobal
-.endmacro emit_global_close
-.
-.macro emit_presolution()
-\tGlobalSection(SolutionConfigurationPlatforms) = preSolution
-\t\tStaticDebug|Win32 = StaticDebug|Win32
-\t\tStaticDebug|x64 = StaticDebug|x64
-\t\tStaticRelease|Win32 = StaticRelease|Win32
-\t\tStaticRelease|x64 = StaticRelease|x64
-\t\tStaticDebug|ARM = StaticDebug|ARM
-\t\tStaticDebug|ARM64 = StaticDebug|ARM64
-\t\tStaticRelease|ARM = StaticRelease|ARM
-\t\tStaticRelease|ARM64 = StaticRelease|ARM64
-\tEndGlobalSection
-.endmacro emit_presolution
-.
-.macro emit_global_postsolution_open()
-\tGlobalSection(ProjectConfigurationPlatforms) = postSolution
-.endmacro emit_global_postsolution_open
-.
-.macro emit_global_postsolution_close()
-\tEndGlobalSection
-.endmacro emit_global_postsolution_close
-.
-.macro emit_library_crossproduct(uuid)
-\t\t{$(my.uuid:upper)}.StaticDebug|Win32.ActiveCfg = DebugLIB|Win32
-\t\t{$(my.uuid:upper)}.StaticDebug|Win32.Build.0 = DebugLIB|Win32
-\t\t{$(my.uuid:upper)}.StaticDebug|x64.ActiveCfg = DebugLIB|x64
-\t\t{$(my.uuid:upper)}.StaticDebug|x64.Build.0 = DebugLIB|x64
-\t\t{$(my.uuid:upper)}.StaticRelease|Win32.ActiveCfg = ReleaseLIB|Win32
-\t\t{$(my.uuid:upper)}.StaticRelease|Win32.Build.0 = ReleaseLIB|Win32
-\t\t{$(my.uuid:upper)}.StaticRelease|x64.ActiveCfg = ReleaseLIB|x64
-\t\t{$(my.uuid:upper)}.StaticRelease|x64.Build.0 = ReleaseLIB|x64
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM.ActiveCfg = DebugLIB|ARM
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM.Build.0 = DebugLIB|ARM
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM64.ActiveCfg = DebugLIB|ARM64
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM64.Build.0 = DebugLIB|ARM64
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM.ActiveCfg = ReleaseLIB|ARM
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM.Build.0 = ReleaseLIB|ARM
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM64.ActiveCfg = ReleaseLIB|ARM64
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM64.Build.0 = ReleaseLIB|ARM64
-.endmacro emit_library_crossproduct
-.
-.macro emit_binary_crossproduct(uuid)
-\t\t{$(my.uuid:upper)}.StaticDebug|Win32.ActiveCfg = DebugSEXE|Win32
-\t\t{$(my.uuid:upper)}.StaticDebug|Win32.Build.0 = DebugSEXE|Win32
-\t\t{$(my.uuid:upper)}.StaticDebug|x64.ActiveCfg = DebugSEXE|x64
-\t\t{$(my.uuid:upper)}.StaticDebug|x64.Build.0 = DebugSEXE|x64
-\t\t{$(my.uuid:upper)}.StaticRelease|Win32.ActiveCfg = ReleaseSEXE|Win32
-\t\t{$(my.uuid:upper)}.StaticRelease|Win32.Build.0 = ReleaseSEXE|Win32
-\t\t{$(my.uuid:upper)}.StaticRelease|x64.ActiveCfg = ReleaseSEXE|x64
-\t\t{$(my.uuid:upper)}.StaticRelease|x64.Build.0 = ReleaseSEXE|x64
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM.ActiveCfg = DebugSEXE|ARM
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM.Build.0 = DebugSEXE|ARM
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM64.ActiveCfg = DebugSEXE|ARM64
-\t\t{$(my.uuid:upper)}.StaticDebug|ARM64.Build.0 = DebugSEXE|ARM64
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM.ActiveCfg = ReleaseSEXE|ARM
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM.Build.0 = ReleaseSEXE|ARM
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM64.ActiveCfg = ReleaseSEXE|ARM64
-\t\t{$(my.uuid:upper)}.StaticRelease|ARM64.Build.0 = ReleaseSEXE|ARM64
-.endmacro emit_binary_crossproduct
-.
-.macro emit_solution_properties()
-\tGlobalSection(SolutionProperties) = preSolution
-\t\tHideSolutionNode = FALSE
-\tEndGlobalSection
-.endmacro emit_solution_properties
-.
-.endtemplate
-.template 0
-###############################################################################
-# Generation
-###############################################################################
-function generate_solutions(path_prefix, generate)
- define my.generate = generate_solutions.generate
-
- for my.generate->vs.version as _version by _version.value
- define my.toolset = my.generate->msvc->toolset(\
- _toolset.name = _version.value, _toolset)
-
- for my.generate.repository as _repository by _repository.name
- require(_repository, "repsoitory", "name")
-
- define my.absolute_path = join(join(global.root, my.path_prefix, \
- _repository.name))
-
- define my.sln_path = solution_relative_path(_repository, \
- my.path_prefix, _version.value)
-
- define my.sln_filename = solution_file(_repository, \
- my.path_prefix, _version.value)
-
- create_directory(my.sln_path)
- notify(my.sln_filename)
- output(my.sln_filename)
- emit_solution(my.toolset, _repository)
- close
- endfor _repository
- endfor _version
-endfunction # generate_solutions
-
-###############################################################################
-# Execution
-###############################################################################
-[global].root = ".."
-[global].trace = 0
-[gsl].ignorecase = 0
-
-# Note: expected context root libbitcoin-build directory
-gsl from "library/math.gsl"
-gsl from "library/string.gsl"
-gsl from "library/collections.gsl"
-gsl from "utilities.gsl"
-
-generate_solutions("output", generate)
-
-.endtemplate
diff --git a/templates/gsl.version.hpp b/templates/gsl.version.hpp
deleted file mode 100644
index 6a9f7a51..00000000
--- a/templates/gsl.version.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-.template 0
-###############################################################################
-# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
-#
-# GSL generate version.hpp.
-#
-# This is a code generator built using the iMatix GSL code generation
-# language. See https://github.com/imatix/gsl for details.
-###############################################################################
-# Functions
-###############################################################################
-
-###############################################################################
-# Macros
-###############################################################################
-.endtemplate
-.template 1
-.
-.macro render_version(version, upper_repository)
-. define my.version = render_version.version
-. new version as _version
-. split_version(_version, my.version)
-#ifndef $(my.upper_repository)_VERSION_HPP
-#define $(my.upper_repository)_VERSION_HPP
-
-/**
- * The semantic version of this repository as: [major].[minor].[patch]
- * For interpretation of the versioning scheme see: http://semver.org
- */
-
-#define $(my.upper_repository)_VERSION "$(_version.major).$(_version.minor).$(_version.patch)"
-#define $(my.upper_repository)_MAJOR_VERSION $(_version.major)
-#define $(my.upper_repository)_MINOR_VERSION $(_version.minor)
-#define $(my.upper_repository)_PATCH_VERSION $(_version.patch)
-
-#endif
-. endnew
-.endmacro # render_version
-.
-.endtemplate
-.template 0
-###############################################################################
-# Generation
-###############################################################################
-function generate_version(path_prefix)
- for generate.repository by name as _repository
- define my.primary = bitcoin_to_include(_repository.name)
- define my.upper_repository = "$(_repository.name:c,upper)"
- define my.version = _repository.version
- for _repository.make as _make
- for _make.product as _product where is_bitcoin_headers(_product)
- for _product.files as _files
-
- # We are writing into local primary includes (not installdir).
- define my.include = join(join(my.path_prefix,\
- canonical_path_name(_repository)), _files.path)
- define my.path = "$(my.include)/$(my.primary)"
- create_directory(my.path)
-
- define my.out_file = "$(my.path)/version.hpp"
- notify(my.out_file)
- output(my.out_file)
-
- c_copyleft(_repository.name)
- render_version(my.version, my.upper_repository)
-
- close
- endfor _files
- endfor _product
- endfor _make
- endfor _repository
-endfunction # generate_version
-.endtemplate
-.template 0
-###############################################################################
-# Execution
-###############################################################################
-[global].root = ".."
-[global].trace = 0
-[gsl].ignorecase = 0
-
-# Note: expected context root libbitcoin-build directory
-gsl from "library/math.gsl"
-gsl from "library/string.gsl"
-gsl from "library/collections.gsl"
-gsl from "utilities.gsl"
-
-generate_version("output")
-
-.endtemplate
diff --git a/templates/msbuild/packages.config.gsl b/templates/msbuild/packages.config.gsl
new file mode 100644
index 00000000..0f211996
--- /dev/null
+++ b/templates/msbuild/packages.config.gsl
@@ -0,0 +1,197 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate libbitcoin packages.config
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+[gsl].shuffle = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/xml-output.gsl"
+gsl from "../lib/msbuild.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_packages_config(configuration)
+ define my.configuration = generate_packages_config.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ for my.template.tools as _tools by _tools.set
+ for my.configuration.repository as _repository
+ for _repository. as _target where is_target_element(_target)
+ generate_target_packages_config(_target, _repository, \
+ my.configuration, _tools, my.template)
+ endfor
+ endfor
+ endfor
+endfunction
+
+function generate_target_packages_config(target, repository, configuration, tooling, meta)
+ define my.target = generate_target_packages_config.target
+ define my.repository = generate_target_packages_config.repository
+ define my.configuration = generate_target_packages_config.configuration
+ define my.tooling = generate_target_packages_config.tooling
+ define my.meta = generate_target_packages_config.meta
+
+ define my.filename = "packages.config"
+
+ define my.output_path = path_append(my.configuration->templates.resultpath, \
+ path_append(my.repository.name, \
+ path_append(my.meta.outpath, \
+ path_append(my.tooling.outpath, \
+ target_name(my.target)))))
+
+ create_directory(my.output_path)
+
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ emit_packages_config(my.target, my.repository, my.configuration, \
+ my.tooling, my.meta)
+
+ close
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+
+function compute_packages(result, target, repository, configuration, tooling, meta)
+ define my.result = compute_packages.result
+ define my.target = compute_packages.target
+ define my.repository = compute_packages.repository
+ define my.configuration = compute_packages.configuration
+ define my.tooling = compute_packages.tooling
+ define my.meta = compute_packages.meta
+
+ define my.toolchain = my.configuration->toolchain(\
+ this.name = my.tooling.chain, this)
+
+ define my.toolset = my.toolchain->toolset(\
+ this.name = my.tooling.set, this)
+
+ new dependencies as _dependencies
+ target_dependency_list(_dependencies, my.target, my.repository, my.configuration)
+ for _dependencies.dependency as _depend where defined(_depend->nuget)
+ # address non-component resources
+ for _depend->nuget.resource as _resource where \
+ !defined(_resource.component)
+
+ define my.found = 0
+
+ for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+
+ my.found = 1
+
+ new my.result.package as _result
+ _result.name = _package.name
+ _result.version = _package.version
+ endnew
+ endfor
+
+ if !my.found
+ echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+ endif
+ endfor
+
+ # address component resources
+ for _depend.component as _component
+ for _depend->nuget.resource as _resource where \
+ defined(_resource.component) & (_resource.component = _component.name)
+
+ define my.found = 0
+
+ for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+
+ my.found = 1
+
+ new my.result.package as _result
+ _result.name = _package.name
+ _result.version = _package.version
+ endnew
+ endfor
+
+ if !my.found
+ echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+ endif
+ endfor
+ endfor
+ endfor
+ endnew
+endfunction
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_packages_config(target, repository, configuration, tooling, meta)
+. define my.target = emit_packages_config.target
+. define my.repository = emit_packages_config.repository
+. define my.configuration = emit_packages_config.configuration
+. define my.tooling = emit_packages_config.tooling
+. define my.meta = emit_packages_config.meta
+.
+
+.
+. copyleft(my.repository.name)
+.
+
+. emit_packages(my.target, my.repository, my.configuration, my.tooling, my.meta, " ")
+
+.
+.endmacro # emit_packagees_config
+.
+.macro emit_packages(target, repository, configuration, tooling, meta, indent)
+. define my.target = emit_packages.target
+. define my.repository = emit_packages.repository
+. define my.configuration = emit_packages.configuration
+. define my.tooling = emit_packages.tooling
+. define my.meta = emit_packages.meta
+. define my.indent = emit_packages.indent
+.
+. new packages as _packages
+. compute_packages(_packages, my.target, my.repository, \
+ my.configuration, my.tooling, my.meta)
+.
+. for _packages.package as _package by _package.name
+$(my.indent)
+. endfor
+. endnew
+.
+.endmacro # emit_packages
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_packages_config(configuration)
+
+.endtemplate
diff --git a/templates/msbuild/sln.gsl b/templates/msbuild/sln.gsl
new file mode 100644
index 00000000..cf96e22a
--- /dev/null
+++ b/templates/msbuild/sln.gsl
@@ -0,0 +1,174 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate libbitcoin .sln
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+[gsl].shuffle = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/msbuild.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_sln(configuration)
+ define my.configuration = generate_sln.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.resource_name = ".sln"
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ for my.template.tools as _tools by _tools.set
+ for my.configuration.repository as _repository
+ define my.output_path = path_append(my.configuration->templates.resultpath, \
+ path_append(_repository.name, \
+ path_append(my.template.outpath, _tools.outpath)))
+
+ define my.filename = "$(_repository.name).sln"
+
+ create_directory(my.output_path)
+
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ define my.toolchain = my.configuration->toolchain(this.name = _tools.chain, this)
+ copy _tools to my.toolchain
+
+ emit_sln(_repository, my.configuration, my.toolchain, my.template)
+ close
+ endfor
+ endfor
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_sln(repository, configuration, toolchain, meta)
+. define my.repository = emit_sln.repository
+. define my.configuration = emit_sln.configuration
+. define my.toolchain = emit_sln.toolchain
+. define my.meta = emit_sln.meta
+.
+
+Microsoft Visual Studio Solution File, Format Version $(my.toolchain->msvc.format)
+# Visual Studio $(my.toolchain->msvc.year)
+VisualStudioVersion = $(my.toolchain->msvc->version.value)
+MinimumVisualStudioVersion = $(my.toolchain->msvc->version.min)
+.
+. for my.repository. as _target where is_target_element(_target) & defined(_target.uuid)
+. emit_project(_target, my.repository, my.configuration, my.toolchain, my.meta)
+. endfor
+.
+Global
+.
+. emit_solution_matrix(my.toolchain, "\t")
+. emit_project_matrix(my.repository, my.configuration, my.toolchain, my.meta, "\t")
+. emit_solution_properties("\t")
+.
+EndGlobal
+.
+.
+.endmacro # emit_sln
+.
+.macro emit_project(target, repository, configuration, toolchain, meta)
+. define my.target = emit_project.target
+. define my.repository = emit_project.repository
+. define my.configuration = emit_project.configuration
+. define my.toolchain = emit_project.toolchain
+. define my.meta = emit_project.meta
+.
+. define my.project_type = my.toolchain->msvc->type(.name = "c++").uuid
+. define my.path = project_relative_path(my.target, my.meta, my.toolchain->tools)
+. define my.sub = substitute_separator(my.path, "/", "\\")
+.
+Project("{$(my.project_type)}") = "$(target_name(my.target))", "$(my.sub)", "{$(my.target.uuid:upper)}"
+EndProject
+.
+.endmacro # emit_project
+.
+.macro emit_solution_matrix(toolchain, indent)
+. define my.toolchain = emit_solution_matrix.toolchain
+. define my.indent = emit_solution_matrix.indent
+.
+$(my.indent)GlobalSection(SolutionConfigurationPlatforms) = preSolution
+. for my.toolchain->msvc->axis(.name = "configuration").entry as _config
+. for my.toolchain->msvc->axis(.name = "platform").entry as _platform
+\t$(my.indent)$(_config.value)|$(_platform.value) = $(_config.value)|$(_platform.value)
+. endfor
+. endfor
+$(my.indent)EndGlobalSection
+.endmacro # emit_solution_matrix
+.
+.macro emit_project_matrix(repository, configuration, toolchain, meta, indent)
+. define my.repository = emit_project_matrix.repository
+. define my.configuration = emit_project_matrix.configuration
+. define my.toolchain = emit_project_matrix.toolchain
+. define my.meta = emit_project_matrix.meta
+. define my.indent = emit_project_matrix.indent
+.
+$(my.indent)GlobalSection(ProjectConfigurationPlatforms) = postSolution
+. for my.repository. as _target where is_target_element(_target) & defined(_target.uuid)
+. emit_target_matrix(_target, my.toolchain, "\t$(my.indent)")
+. endfor
+$(my.indent)EndGlobalSection
+.endmacro # emit_presolution_matrix
+.
+.macro emit_target_matrix(target, toolchain, indent)
+. define my.target = emit_target_matrix.target
+. define my.toolchain = emit_target_matrix.toolchain
+. define my.indent = emit_target_matrix.indent
+.
+. for my.toolchain->msvc->axis(.name = "configuration").entry as _config
+. define my.target_config = _config->$(name(my.target)).value
+. for my.toolchain->msvc->axis(.name = "platform").entry as _platform
+$(my.indent){$(my.target.uuid:upper)}.$(_config.value)|$(_platform.value).ActiveCfg = $(my.target_config)|$(_platform.value)
+$(my.indent){$(my.target.uuid:upper)}.$(_config.value)|$(_platform.value).Build.0 = $(my.target_config)|$(_platform.value)
+. endfor
+. endfor
+.endmacro # emit_target_matrix
+.
+.macro emit_solution_properties(indent)
+. define my.indent = emit_solution_properties.indent
+.
+$(my.indent)GlobalSection(SolutionProperties) = preSolution
+\t$(my.indent)HideSolutionNode = FALSE
+$(my.indent)EndGlobalSection
+.
+.endmacro # emit_solution_properties
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_sln(configuration)
+
+.endtemplate
diff --git a/templates/msbuild/vcxproj.filters.gsl b/templates/msbuild/vcxproj.filters.gsl
new file mode 100644
index 00000000..b46cc3c5
--- /dev/null
+++ b/templates/msbuild/vcxproj.filters.gsl
@@ -0,0 +1,324 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate libbitcoin vcxproj.filters
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+[gsl].shuffle = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/xml-output.gsl"
+gsl from "../lib/msbuild.gsl"
+gsl from "../lib/uuid.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_vcxproj_filters(configuration)
+ define my.configuration = generate_vcxproj_filters.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ for my.template.tools as _tools by _tools.set
+ for my.configuration.repository as _repository
+ for _repository. as _target where is_target_element(_target)
+ generate_target_vcxproj_filters(_target, _repository, \
+ my.configuration, _tools, my.template)
+ endfor
+ endfor
+ endfor
+endfunction
+
+function generate_target_vcxproj_filters(target, repository, configuration, tooling, meta)
+ define my.target = generate_target_vcxproj_filters.target
+ define my.repository = generate_target_vcxproj_filters.repository
+ define my.configuration = generate_target_vcxproj_filters.configuration
+ define my.tooling = generate_target_vcxproj_filters.tooling
+ define my.meta = generate_target_vcxproj_filters.meta
+
+ define my.filename = "$(target_name(my.target)).vcxproj.filters"
+
+ define my.output_path = path_append(my.configuration->templates.resultpath, \
+ path_append(my.repository.name, \
+ path_append(my.meta.outpath, \
+ path_append(my.tooling.outpath, \
+ target_name(my.target)))))
+
+ create_directory(my.output_path)
+
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ emit_vcxproj_filters(my.target, my.repository, my.configuration, \
+ my.tooling, my.meta)
+
+ close
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+function matches_substitution(substitutions, path)
+ define my.substitutions = matches_substitution.substitutions
+ define my.path = matches_substitution.path
+
+ for my.substitutions.substitution as _sub
+ if starts_with(my.path, _sub.absolute_path)
+ return _sub
+ endif
+ endfor
+endfunction
+
+function populate_uuid(files, seed)
+ define my.files = populate_uuid.files
+ my.files.uuid = populate_uuid.seed
+ define my.seed = uuid_inc(my.files.uuid)
+
+ for my.files.directory as _directory
+ my.seed = populate_uuid(_directory, my.seed)
+ endfor
+
+ return my.seed
+endfunction
+
+function accumulate_filters(result, files, substitutions, target)
+ define my.result = accumulate_filters.result
+ define my.files = accumulate_filters.files
+ define my.substitutions = accumulate_filters.substitutions
+ define my.target = accumulate_filters.target
+
+ if defined(my.files.path)
+ define my.path = "$(my.files.name)"
+ define my.applicable_sub = matches_substitution(my.substitutions, my.path)
+ define my.sanitized_path = \
+ (string.length(my.applicable_sub.absolute_path) < string.length(my.path)) ??\
+ string.substr(my.path, \
+ string.length(my.applicable_sub.absolute_path), string.length(my.path) - 1) ?\
+ ""
+ define my.filter_path = my.sanitized_path
+ if defined(my.applicable_sub.filter)
+ my.filter_path = path_append(my.applicable_sub.filter, my.sanitized_path)
+ endif
+ if ends_with(my.filter_path, "/")
+ my.filter_path = string.substr(my.filter_path, 0, string.length(my.filter_path) - 2)
+ endif
+
+ if (count(my.result.filter, this.path = my.filter_path, this) = 0)
+ new my.result.filter as _filter
+ _filter.path = my.filter_path
+ _filter.target_uuid = my.target.uuid
+ _filter.files_uuid = my.files.uuid
+ endnew
+ else
+ echo "Collision using filter path '$(my.filter_path)'."
+ endif
+ endif
+
+ for my.files.directory as _directory
+ accumulate_filters(my.result, _directory, my.substitutions, my.target)
+ endfor
+endfunction
+
+function accumulate_items(result, files, substitutions, filters)
+ define my.result = accumulate_items.result
+ define my.files = accumulate_items.files
+ define my.substitutions = accumulate_items.substitutions
+ define my.filters = accumulate_items.filters
+
+ for my.files.file as _file where matches_filters(my.filters, _file.name)
+ define my.applicable_sub = matches_substitution(my.substitutions, _file.path)
+ define my.sanitized_path = string.substr(_file.path, string.length(my.applicable_sub.absolute_path), string.length(_file.path) - 1)
+
+ define my.filename = path_append(my.applicable_sub.relative_path_prefix, \
+ path_append(my.sanitized_path, _file.name))
+
+ define my.filter_path = my.sanitized_path
+
+ if defined(my.applicable_sub.filter)
+ my.filter_path = path_append(my.applicable_sub.filter, my.sanitized_path)
+ endif
+
+ if ends_with(my.filter_path, "/")
+ my.filter_path = string.substr(my.filter_path, 0, string.length(my.filter_path) - 2)
+ endif
+
+ define my.name = path(my.filename)
+ define my.filter = path(my.filter_path)
+
+ if (count(my.result.item, this.name = my.name, this) = 0)
+ new my.result.item as _item
+ _item.name = my.name
+ _item.filter = my.filter
+ endnew
+ else
+ echo "Collision using item name '$(my.name)'."
+ endif
+ endfor
+
+ for my.files.directory as _directory
+ accumulate_items(my.result, _directory, my.substitutions, my.filters)
+ endfor
+endfunction
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_vcxproj_filters(target, repository, configuration, tooling, meta)
+. define my.target = emit_vcxproj_filters.target
+. define my.repository = emit_vcxproj_filters.repository
+. define my.configuration = emit_vcxproj_filters.configuration
+. define my.tooling = emit_vcxproj_filters.tooling
+. define my.meta = emit_vcxproj_filters.meta
+.
+. define my.indent = " "
+. define my.seed = 0
+. define my.toolchain = my.configuration->toolchain(this.name = my.tooling.chain, this)
+. define my.version = (name(my.target) = "library") ?? \
+ my.toolchain->msbuild->version(this.type = "lib", this).value ? \
+ my.toolchain->msbuild->version(this.type = "bin", this).value
+.
+
+.
+. copyleft(my.repository.name)
+.
+
+.
+. new substitutions as _substitutions
+. new directory as _files
+. define my.absolute_root = repository_absolute_path(\
+ my.repository, my.configuration)
+. define my.intended_prefix = my.meta->path.prefix
+.
+. populate_files(_substitutions, _files, my.meta->discovery, \
+ my.target, my.absolute_root, my.intended_prefix)
+.
+. my.seed = populate_uuid(_files, my.seed)
+.
+. # Filters
+
+. emit_filters(_files, _substitutions, my.target, my.indent)
+
+.
+. # ClCompile
+. new items as _items
+. accumulate_items(_items, _files, _substitutions, my.meta->sources)
+.
+. if (count(_items.item) > 0)
+
+. emit_items("ClCompile", _items, my.indent)
+
+. endif
+. endnew
+.
+. # ClInclude
+. new items as _items
+. accumulate_items(_items, _files, _substitutions, my.meta->headers)
+.
+. if (count(_items.item) > 0)
+
+. emit_items("ClInclude", _items, my.indent)
+
+. endif
+. endnew
+.
+. # None
+. new items as _items
+. accumulate_items(_items, _files, _substitutions, my.meta->other)
+.
+. new _items.item as _item
+. _item.name = "packages.config"
+. endnew
+.
+
+. emit_items("None", _items, my.indent)
+
+. endnew
+.
+. # Natvis
+
+
+
+.
+. # ResourceCompile
+. new items as _items
+. accumulate_items(_items, _files, _substitutions, my.meta->resource)
+.
+. if (count(_items.item) > 0)
+
+. emit_items("ResourceCompile", _items, my.indent)
+
+. endif
+. endnew
+. endnew
+. endnew
+.
+
+.
+.endmacro # emit_vcxproj_filters
+.
+.macro emit_filters(files, substitutions, target, indent)
+. define my.files = emit_filters.files
+. define my.substitutions = emit_filters.substitutions
+. define my.target = emit_filters.target
+. define my.indent = emit_filters.indent
+.
+. new filters as _filters
+. accumulate_filters(_filters, my.files, my.substitutions, my.target)
+.
+. for _filters.filter as _filter by _filter.path
+$(my.indent)
+ $(my.indent){$(to_uuid(_filter.target_uuid, _filter.files_uuid):upper)}
+$(my.indent)
+. endfor
+. endnew
+.endmacro # emit_filters
+.
+.macro emit_items(item_name, items, indent)
+. define my.item_name = emit_items.item_name
+. define my.items = emit_items.items
+. define my.indent = emit_items.indent
+.
+. for my.items.item as _item by _item.name
+. my.lineend = defined(_item.filter) ?? ">" ? " />"
+$(my.indent)<$(my.item_name) Include="$(_item.name)"$(my.lineend)
+.
+. if defined(_item.filter)
+ $(my.indent)$(_item.filter)
+$(my.indent)$(my.item_name)>
+. endif
+. endfor
+.
+.endmacro # emit_items
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_vcxproj_filters(configuration)
+
+.endtemplate
diff --git a/templates/msbuild/vcxproj.gsl b/templates/msbuild/vcxproj.gsl
new file mode 100644
index 00000000..fd64c94d
--- /dev/null
+++ b/templates/msbuild/vcxproj.gsl
@@ -0,0 +1,452 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate libbitcoin vcxproj
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+[gsl].shuffle = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/xml-output.gsl"
+gsl from "../lib/msbuild.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_vcxproj(configuration)
+ define my.configuration = generate_vcxproj.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ for my.template.tools as _tools by _tools.set
+ for my.configuration.repository as _repository
+ for _repository. as _target where is_target_element(_target)
+ generate_target_vcxproj(_target, _repository, \
+ my.configuration, _tools, my.template)
+ endfor
+ endfor
+ endfor
+endfunction
+
+function generate_target_vcxproj(target, repository, configuration, tooling, meta)
+ define my.target = generate_target_vcxproj.target
+ define my.repository = generate_target_vcxproj.repository
+ define my.configuration = generate_target_vcxproj.configuration
+ define my.tooling = generate_target_vcxproj.tooling
+ define my.meta = generate_target_vcxproj.meta
+
+ define my.filename = "$(target_name(my.target)).vcxproj"
+
+ define my.output_path = path_append(my.configuration->templates.resultpath, \
+ path_append(my.repository.name, \
+ path_append(my.meta.outpath, \
+ path_append(my.tooling.outpath, \
+ target_name(my.target)))))
+
+ create_directory(my.output_path)
+
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ emit_vcxproj(my.target, my.repository, my.configuration, \
+ my.tooling, my.meta)
+
+ close
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+function matches_substitution(substitutions, path)
+ define my.substitutions = matches_substitution.substitutions
+ define my.path = matches_substitution.path
+
+ for my.substitutions.substitution as _sub
+ if starts_with(my.path, _sub.absolute_path)
+ return _sub
+ endif
+ endfor
+endfunction
+
+function nuget_target(package)
+ define my.package = nuget_target.package
+ define my.prefix = "\$(NuGetPackageRoot)$(my.package.name).$(my.package.version)"
+ define my.relative_path = defined(my.package.targets) ?? my.package.targets ? "build"
+ define my.targets_file = "$(my.package.name).targets"
+
+ return "$(my.prefix)/$(my.relative_path)/$(my.targets_file)"
+endfunction
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_vcxproj(target, repository, configuration, tooling, meta)
+. define my.target = emit_vcxproj.target
+. define my.repository = emit_vcxproj.repository
+. define my.configuration = emit_vcxproj.configuration
+. define my.tooling = emit_vcxproj.tooling
+. define my.meta = emit_vcxproj.meta
+.
+. define my.item_indent = " "
+. define my.toolchain = my.configuration->toolchain(this.name = my.tooling.chain, this)
+. define my.toolset = my.toolchain->toolset(this.name = my.tooling.set, this)
+. define my.version = (name(my.target) = "library") ?? \
+ my.toolchain->msbuild->version(this.type = "lib", this).value ? \
+ my.toolchain->msbuild->version(this.type = "bin", this).value
+.
+
+.
+. copyleft(my.repository.name)
+.
+
+
+.
+. if !(name(my.target) = "library")
+ Application
+. endif
+.
+ $(my.toolset.compiler)
+ {$(my.target.uuid:upper)}
+ $(target_name(my.target))
+
+.
+. emit_project_configuration(my.target, my.repository, my.configuration, my.toolchain, my.toolset, my.meta, " ")
+.
+. if (name(my.target) = "library")
+. emit_propertygroup_configuration(" ")
+. endif
+.
+
+
+
+
+
+
+
+.
+. new substitutions as _substitutions
+. new directory as _files
+. define my.absolute_root = repository_absolute_path(\
+ my.repository, my.configuration)
+. define my.intended_prefix = my.meta->path.prefix
+.
+. populate_files(_substitutions, _files, my.meta->discovery, \
+ my.target, my.absolute_root, my.intended_prefix)
+.
+. # ClCompile
+
+
+. new conflicts as _conflicts
+. emit_items("ClCompile", _files, _substitutions, \
+ my.meta->sources, my.item_indent, _conflicts)
+. endnew
+
+. # ClInclude
+
+. emit_items("ClInclude", _files, _substitutions, my.meta->headers, my.item_indent)
+
+. # None
+
+. emit_items("None", _files, _substitutions, my.meta->other, my.item_indent)
+
+
+. # ResourceCompile
+
+. emit_items("ResourceCompile", _files, _substitutions, my.meta->resource, my.item_indent)
+
+. emit_import_projects(my.target, my.repository, my.configuration, \
+ my.toolchain, my.toolset, my.meta, " ")
+.
+. endnew
+. endnew
+. emit_ensure_nuget_imports(my.target, my.repository, my.configuration, \
+ my.toolchain, my.toolset, my.meta, " ")
+.
+. if !(name(my.target) = "library")
+. emit_project_references(my.target, my.repository, my.configuration, " ")
+. endif
+.
+. # Natvis
+
+
+
+.
+
+.
+.endmacro # emit_vcxproj
+.
+.macro emit_project_configuration(target, repository, configuration, \
+ toolchain, toolset, meta, indent)
+.
+. define my.target = emit_project_configuration.target
+. define my.repository = emit_project_configuration.repository
+. define my.configuration = emit_project_configuration.configuration
+. define my.toolchain = emit_project_configuration.toolchain
+. define my.toolset = emit_project_configuration.toolset
+. define my.meta = emit_project_configuration.meta
+. define my.indent = emit_project_configuration.indent
+.
+$(my.indent)
+.
+. for my.toolchain->msvc->axis(.name = "configuration").entry as _config
+. define my.target_config = _config->$(name(my.target)).value
+. for my.toolchain->msvc->axis(.name = "platform").entry as _platform
+.
+ $(my.indent)
+ $(my.indent)$(my.target_config)
+ $(my.indent)$(_platform.value)
+ $(my.indent)
+. endfor
+. endfor
+.
+$(my.indent)
+.
+.endmacro # emit_project_configuration
+.
+.macro emit_items(item_name, files, substitutions, filters, indent, conflicts)
+. define my.item_name = emit_items.item_name
+. define my.files = emit_items.files
+. define my.substitutions = emit_items.substitutions
+. define my.filters = emit_items.filters
+. define my.indent = emit_items.indent
+. define my.conflicts = emit_items.conflicts?
+.
+. for my.files.file as _file where matches_filters(my.filters, _file.name)
+. define my.conflicted = 0
+. define my.applicable_sub = matches_substitution(my.substitutions, _file.path)
+. define my.sanitized_path = string.substr(_file.path, string.length(my.applicable_sub.absolute_path), string.length(_file.path) - 1)
+. define my.filename = path_append(my.applicable_sub.relative_path_prefix, \
+ path_append(my.sanitized_path, _file.name))
+. define my.filter_path = my.sanitized_path
+. if defined(my.applicable_sub.filter)
+. my.filter_path = path_append(my.applicable_sub.filter, my.sanitized_path)
+. endif
+. if ends_with(my.filter_path, "/")
+. my.filter_path = string.substr(my.filter_path, 0, string.length(my.filter_path) - 2)
+. endif
+.
+. define my.splitpoint = string.locate_last(_file.name, ".")
+. define my.filename_base = string.substr(_file.name, 0, my.splitpoint - 1)
+.
+. if defined(my.conflicts)
+. if (count(my.conflicts.conflict, count.name = my.filename_base) > 0)
+. my.conflicted = 1
+. else
+. new my.conflicts.conflict as _conflict
+. _conflict.name = my.filename_base
+. endnew
+. endif
+. endif
+.
+. if my.conflicted
+. define my.path_to_prefix = string.replace(my.sanitized_path, "/|_")
+. define my.disambiguated = "$(my.applicable_sub.unprefixed_path)$(my.path_to_prefix)$(my.filename_base).obj"
+$(my.indent)<$(my.item_name) Include="$(path(my.filename))">
+ $(my.indent)\$(IntDir)$(my.disambiguated)
+$(my.indent)$(my.item_name)>
+. else
+$(my.indent)<$(my.item_name) Include="$(path(my.filename))" />
+. endif
+. endfor
+.
+. for my.files.directory as _directory
+. emit_items(my.item_name, _directory, my.substitutions, my.filters, \
+ my.indent, my.conflicts)
+. endfor
+.endmacro # emit_items
+.
+.macro emit_import_projects(target, repository, configuration, toolchain, toolset, meta, indent)
+. define my.target = emit_import_projects.target
+. define my.repository = emit_import_projects.repository
+. define my.configuration = emit_import_projects.configuration
+. define my.toolchain = emit_import_projects.toolchain
+. define my.toolset = emit_import_projects.toolset
+. define my.meta = emit_import_projects.meta
+. define my.indent = emit_import_projects.indent
+.
+$(my.indent)
+$(my.indent)
+$(my.indent)
+.
+. new dependencies as _dependencies
+. target_dependency_list(_dependencies, my.target, my.repository, my.configuration)
+. for _dependencies.dependency as _depend where defined(_depend->nuget)
+. for _depend->nuget.resource as _resource where \
+ !defined(_resource.component)
+.
+. define my.found = 0
+.
+. for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+.
+. my.found = 1
+.
+. define my.nutarget = path(nuget_target(_package))
+ $(my.indent)
+.
+. endfor
+.
+. if !my.found
+. echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+. endif
+. endfor
+.
+. # address component resources
+. for _depend.component as _component
+. for _depend->nuget.resource as _resource where \
+ defined(_resource.component) & (_resource.component = _component.name)
+.
+. define my.found = 0
+.
+. for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+.
+. my.found = 1
+.
+. define my.nutarget = path(nuget_target(_package))
+ $(my.indent)
+.
+. endfor
+.
+. if !my.found
+. echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+. endif
+. endfor
+. endfor
+. endfor
+. endnew
+.
+$(my.indent)
+.endmacro # emit_import_projects
+.
+.macro emit_ensure_nuget_imports(target, repository, configuration, toolchain, toolset, meta, indent)
+. define my.target = emit_ensure_nuget_imports.target
+. define my.repository = emit_ensure_nuget_imports.repository
+. define my.configuration = emit_ensure_nuget_imports.configuration
+. define my.toolchain = emit_ensure_nuget_imports.toolchain
+. define my.toolset = emit_ensure_nuget_imports.toolset
+. define my.meta = emit_ensure_nuget_imports.meta
+. define my.indent = emit_ensure_nuget_imports.indent
+.
+$(my.indent)
+ $(my.indent)
+ $(my.indent)This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The Missing file is {0}.
+ $(my.indent)
+.
+. new dependencies as _dependencies
+. target_dependency_list(_dependencies, my.target, my.repository, my.configuration)
+. for _dependencies.dependency as _depend where defined(_depend->nuget)
+. for _depend->nuget.resource as _resource where \
+ !defined(_resource.component)
+.
+. define my.found = 0
+.
+. for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+.
+. my.found = 1
+.
+. define my.nutarget = path(nuget_target(_package))
+ $(my.indent)
+.
+. endfor
+.
+. if !my.found
+. echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+. endif
+. endfor
+.
+. # address component resources
+. for _depend.component as _component
+. for _depend->nuget.resource as _resource where \
+ defined(_resource.component) & (_resource.component = _component.name)
+.
+. define my.found = 0
+.
+. for _resource.package as _package where \
+ (_package.compiler = my.toolset.compiler)
+.
+. my.found = 1
+.
+. define my.nutarget = path(nuget_target(_package))
+ $(my.indent)
+.
+. endfor
+.
+. if !my.found
+. echo(" Warning: resource '$(_resource.canonical)' did not emit a package with compiler '$(my.toolset.compiler)'.")
+. endif
+. endfor
+. endfor
+. endfor
+. endnew
+.
+$(my.indent)
+.
+.endmacro # emit_ensure_nuget_imports
+.
+.macro emit_propertygroup_configuration(indent)
+. define my.indent = emit_propertygroup_configuration.indent
+.
+$(my.indent)
+ $(my.indent)StaticLibrary
+ $(my.indent)DynamicLibrary
+$(my.indent)
+.endmacro # emit_propertygroup_configuration
+.
+.macro emit_project_references(target, repository, configuration, indent)
+. define my.target = emit_project_references.target
+. define my.repository = emit_project_references.repository
+. define my.configuration = emit_project_references.configuration
+. define my.indent = emit_project_references.indent
+.
+$(my.indent)
+.
+. for my.target.dependency as _depend where \
+ (count(my.repository.library, (count.name = _depend.name) & defined(count.uuid)) > 0)
+.
+. define my.library = my.repository->library(\
+ (this.name = _depend.name) & defined(this.uuid), this)
+.
+ $(my.indent)
+ $(my.indent){$(my.library.uuid:upper)}
+ $(my.indent)
+.
+. endfor
+.
+$(my.indent)
+.
+.endmacro # emit_project_references
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_vcxproj(configuration)
+
+.endtemplate
diff --git a/templates/shell/install-base.gsl b/templates/shell/install-base.gsl
index 004e9dc5..4075dbb4 100644
--- a/templates/shell/install-base.gsl
+++ b/templates/shell/install-base.gsl
@@ -116,10 +116,6 @@ function emit_install_sh(meta, configuration, repository)
endif
endfor
- if (count(_keys.method, count.name = "cmake" | count.name = "preset" | count.name = "gnu") > 0)
- define_helpers_make(my.meta, my.repository, my.configuration)
- endif
-
for _keys.method as _method
if (_method.name = "cmake")
define_build_cmake()
@@ -137,6 +133,18 @@ function emit_install_sh(meta, configuration, repository)
abort "Unrecognized build method '$(_method.name)'."
endif
endfor
+
+ if (count(_keys.method, count.name = "cmake" | count.name = "preset") > 0)
+ define_clean_cmake(my.meta, my.configuration, my.repository)
+ define_install_cmake(my.meta, my.configuration, my.repository)
+ define_test_cmake(my.meta, my.configuration, my.repository)
+ endif
+
+ if (count(_keys.method, count.name = "gnu") > 0)
+ define_clean_gnu(my.meta, my.configuration, my.repository)
+ define_install_gnu(my.meta, my.configuration, my.repository)
+ define_test_gnu(my.meta, my.configuration, my.repository)
+ endif
endnew
define_display_build_variables(my.meta, my.configuration, my.repository, _install)
@@ -164,6 +172,11 @@ function textname(dependency)
return defined(my.dependency.textname) ?? my.dependency.textname ? my.dependency.name
endfunction
+function option_name(dependency)
+ define my.dependency = option_name.dependency
+ return defined(my.dependency.optionname) ?? my.dependency.optionname ? my.dependency.name
+endfunction
+
function substitute(datasource, value, instructions)
define my.datasource = substitute.datasource
define my.result = substitute.value
@@ -208,28 +221,13 @@ function verify_toolchains_supported(dependencies, meta, configuration, reposito
define my.configuration = verify_toolchains_supported.configuration
define my.repository = verify_toolchains_supported.repository
- define my.cmake = defined(my.meta->build(build.method = "cmake"))
- define my.gnu = defined(my.meta->build(build.method = "gnu"))
- define my.msbuild = defined(my.meta->build(build.method = "msbuild"))
- define my.preset = defined(my.meta->build(build.method = "preset"))
-
- # if (my.cmake | my.preset) & (my.gnu)
- # abort "Configurations mixing 'cmake'/'preset' and 'gnu' are not supported."
- # endif
-
- if (my.cmake)
- my.dependencies.toolchain = "cmake"
- my.dependencies.hint_options = "cmake"
- elsif (my.gnu)
- my.dependencies.toolchain = "gnu"
- my.dependencies.hint_options = "gnu"
- elsif (my.msbuild)
- my.dependencies.toolchain = "msbuild"
- my.dependencies.hint_options = "msbuild"
- elsif (my.preset)
- my.dependencies.toolchain = "preset"
- my.dependencies.hint_options = "cmake"
- else
+ define my.canonical = my.meta->build(is_defined_positive(build, "canonical")).method
+
+ if !((my.canonical = "cmake") | \
+ (my.canonical = "gnu") | \
+ (my.canonical = "msbuild") | \
+ (my.canonical = "preset"))
+
abort "Unexpected - missing primary toolchain."
endif
diff --git a/templates/shell/install-bash.gsl b/templates/shell/install-bash.gsl
index cec32504..dbfdc1ef 100644
--- a/templates/shell/install-bash.gsl
+++ b/templates/shell/install-bash.gsl
@@ -37,10 +37,11 @@ function option_flag(option, meta)
define my.meta = option_flag.meta
define my.result = ""
- # Cutting corners here - assumption of boolean configuration (currently true)
- if (count(my.meta.build, count.method = "cmake") > 0)
+ define my.canonical = my.meta->build(is_defined_positive(build, "canonical"))
+
+ if (my.canonical.method = "cmake")
my.result = "-D$(my.option.type)-$(my.option.name)="
- elsif (count(my.meta.build, count.method = "gnu") > 0)
+ elsif (my.canonical.method = "gnu")
if (my.option.type = "enable")
my.result = "---$(my.option.name)"
elsif (my.option.type = "with")
@@ -60,14 +61,16 @@ function option_flag_default(option, meta)
define my.meta = option_flag_default.meta
define my.result = ""
+ define my.canonical = my.meta->build(is_defined_positive(build, "canonical"))
+
define my.positive = ""
define my.negative = ""
# Cutting corners here - assumption of boolean configuration (currently true)
- if (count(my.meta.build, count.method = "cmake") > 0)
+ if (my.canonical.method = "cmake")
my.positive = "ON"
my.negative = "OFF"
- elsif (count(my.meta.build, count.method = "gnu") > 0)
+ elsif (my.canonical.method = "gnu")
if (my.option.type = "enable")
my.positive = "--enable-$(my.option.name)"
my.negative = "--disable-$(my.option.name)"
@@ -365,7 +368,7 @@ $(column_variables("LDLIBS", my.column, my.prefix, my.suffix))
$(column_variables("$(_depend.name:upper)_ROOT", my.column, my.prefix, my.suffix))
. endif
. endfor
-. if (my.install.hint_options = "cmake")
+. if defined(my.meta->build(build.method = "cmake"))
$(column_variables("CMAKE_PREFIX_PATH", my.column, my.prefix, my.suffix))
$(column_variables("CMAKE_INSTALL_PREFIX", my.column, my.prefix, my.suffix))
$(column_variables("CMAKE_INCLUDE_PATH", my.column, my.prefix, my.suffix))
@@ -400,7 +403,7 @@ $(column_variables("CMAKE_LIBRARY_PATH", my.column, my.prefix, my.suffix))
. abort "Expected hint_build value '$(_depend.hint_build)' not found for dependency '$(_depend.name)'."
. endif
.
-$(column_variables("BUILD_$(_depend.name)", my.column, my.prefix, my.suffix))
+$(column_variables("BUILD_$(option_name(_depend))", my.column, my.prefix, my.suffix))
. endfor
.
. if (count(my.install.dependency, this.hint_build = "preset", this) > 0)
@@ -419,6 +422,17 @@ $(column_variables("BUILD_SKIP_TESTS", my.column, my.prefix, my.suffix))
$(column_variables("PARALLEL", my.column, my.prefix, my.suffix))
$(column_variables("PREFIX", my.column, my.prefix, my.suffix))
$(column_variables("DISPLAY_VERBOSE", my.column, my.prefix, my.suffix))
+.
+. define my.canonical = my.meta->build(is_defined_positive(build, "canonical"))
+.
+. if (count(my.meta->build, this.method = "cmake", this) > 0)
+$(fix_column("CONFIGURE_OPTIONS_CMAKE", ": ${CONFIGURE_OPTIONS_CMAKE[*]}", my.column, my.prefix, my.suffix))
+. endif
+.
+. if (count(my.meta->build, this.method = "gnu", this) > 0)
+$(fix_column("CONFIGURE_OPTIONS_GNU", ": ${CONFIGURE_OPTIONS_GNU[*]}", my.column, my.prefix, my.suffix))
+. endif
+.
$(fix_column("CONFIGURE_OPTIONS", ": ${CONFIGURE_OPTIONS[*]}", my.column, my.prefix, my.suffix))
if [[ "${DISPLAY_VERBOSE}" == "yes" ]]; then
$(fix_column("CONFIGURE_OPTIONS_ORIGINAL", ": ${CONFIGURE_OPTIONS_ORIGINAL[*]}", my.column, my.prefix, my.suffix))
@@ -540,7 +554,7 @@ $(fix_column("", option_flag_default(_option, my.meta), my.column, my.prefix, my
. abort "Expected hint_build value '$(_depend.hint_build)' not found for dependency '$(_depend.name)'."
. endif
.
-$(fix_column("--build-$(_depend.name)", "Build $(textname(_depend)) libraries", my.column, my.prefix, my.suffix))
+$(fix_column("--build-$(option_name(_depend))", "Build $(textname(_depend)) libraries", my.column, my.prefix, my.suffix))
. endfor
.
. new build_options as _build_options
@@ -736,17 +750,19 @@ display_configure_options()
fi
.endmacro # define_build_initialize_path
.
-.macro define_helpers_make(meta, repository, configuration)
-. define my.meta = define_helpers_make.meta
-. define my.repository = define_helpers_make.repository
-. define my.configuration = define_helpers_make.configuration
+.macro define_clean_action(meta, configuration, repository, name, command)
+. define my.meta = define_clean_action.meta
+. define my.configuration = define_clean_action.configuration
+. define my.repository = define_clean_action.repository
+. define my.name = define_clean_action.name
+. define my.command = define_clean_action.command
-install_make()
+clean_$(my.name)()
{
local PROJECT="$1"
- shift
+ shift 1
- msg "Preparing to install ${PROJECT}"
+ msg "Preparing to clean ${PROJECT}"
push_directory "${BUILD_SRC_DIR}/${PROJECT}"
@@ -756,24 +772,54 @@ install_make()
push_directory "${BUILD_OBJ_DIR}/${PROJECT}"
fi
- make install
+ disable_exit_on_error
- if [[ ${OS} == Linux ]] && [[ "${PREFIX}" == "/usr/local" ]]; then
- ldconfig
+ $(my.command)
+
+ local RESULT=$?
+
+ if [[ ${RESULT} -ne 0 ]]; then
+ msg_error "Encountered error, please see test.log contents above."
+ exit ${RESULT}
fi
pop_directory # BUILD_OBJ_DIR
pop_directory # BUILD_SRC_DIR/PROJECT
- msg_success "'${PROJECT}' installation complete."
+ msg_success "'${PROJECT}' clean complete."
}
+.endmacro # define_clean_action
+.
+.macro define_clean_cmake(meta, configuration, repository)
+. define my.meta = define_clean_cmake.meta
+. define my.configuration = define_clean_cmake.configuration
+. define my.repository = define_clean_cmake.repository
+.
+. define_clean_action(my.meta, my.configuration, my.repository, \
+ "cmake", "cmake --build . --target clean")
+.
+.endmacro # define_clean_cmake
+.
+.macro define_clean_gnu(meta, configuration, repository)
+. define my.meta = define_clean_gnu.meta
+. define my.configuration = define_clean_gnu.configuration
+. define my.repository = define_clean_gnu.repository
+.
+. define_clean_action(my.meta, my.configuration, my.repository, \
+ "gnu", "make clean")
+.
+.endmacro # define_clean_gnu
+.
+.macro define_test_cmake(meta, configuration, repository)
+. define my.meta = define_test_cmake.meta
+. define my.configuration = define_test_cmake.configuration
+. define my.repository = define_test_cmake.repository
-test_make()
+test_cmake()
{
local PROJECT="$1"
- local TARGET="$2"
- local JOBS="$3"
- shift 3
+ local JOBS="$2"
+ shift 2
msg "Preparing to test ${PROJECT}"
@@ -787,11 +833,7 @@ test_make()
disable_exit_on_error
- if [[ ${JOBS} -gt ${SEQUENTIAL} ]]; then
- make -j${JOBS} ${TARGET} VERBOSE=1
- else
- make ${TARGET} VERBOSE=1
- fi
+ ctest --test-dir .
local RESULT=$?
.
@@ -816,13 +858,20 @@ test_make()
msg_success "'${PROJECT}' test complete."
}
+.endmacro # define_test_cmake
+.
+.macro define_test_gnu(meta, configuration, repository)
+. define my.meta = define_test_gnu.meta
+. define my.configuration = define_test_gnu.configuration
+. define my.repository = define_test_gnu.repository
-clean_make()
+test_gnu()
{
local PROJECT="$1"
- shift 1
+ local JOBS="$2"
+ shift 2
- msg "Preparing to clean ${PROJECT}"
+ msg "Preparing to test ${PROJECT}"
push_directory "${BUILD_SRC_DIR}/${PROJECT}"
@@ -834,21 +883,91 @@ clean_make()
disable_exit_on_error
- make clean
+ if [[ ${JOBS} -gt ${SEQUENTIAL} ]]; then
+ make -j${JOBS} check VERBOSE=1
+ else
+ make check VERBOSE=1
+ fi
local RESULT=$?
+.
+. for my.meta.error as _error where defined(_error.logpath)
+
+ if [[ -e "$(_error.logpath)" ]]; then
+ msg_warn "begin error log: $(_error.logpath)"
+ cat "$(_error.logpath)"
+ msg_warn " end error log: $(_error.logpath)"
+ fi
+. endfor
if [[ ${RESULT} -ne 0 ]]; then
msg_error "Encountered error, please see test.log contents above."
exit ${RESULT}
fi
+ enable_exit_on_error
+
pop_directory # BUILD_OBJ_DIR
pop_directory # BUILD_SRC_DIR/PROJECT
- msg_success "'${PROJECT}' clean complete."
+ msg_success "'${PROJECT}' test complete."
}
-.endmacro # define_helpers_make
+.endmacro # define_test_gnu
+.
+.macro define_install_action(meta, configuration, repository, name, command)
+. define my.meta = define_install_action.meta
+. define my.configuration = define_install_action.configuration
+. define my.repository = define_install_action.repository
+. define my.name = define_install_action.name
+. define my.command = define_install_action.command
+
+install_$(my.name)()
+{
+ local PROJECT="$1"
+ shift
+
+ msg "Preparing to install ${PROJECT}"
+
+ push_directory "${BUILD_SRC_DIR}/${PROJECT}"
+
+ if [[ "${BUILD_OBJ_DIR_RELATIVE}" == "yes" ]]; then
+ push_directory "${BUILD_OBJ_DIR}"
+ else
+ push_directory "${BUILD_OBJ_DIR}/${PROJECT}"
+ fi
+
+ $(my.command)
+
+ if [[ ${OS} == Linux ]] && [[ "${PREFIX}" == "/usr/local" ]]; then
+ ldconfig
+ fi
+
+ pop_directory # BUILD_OBJ_DIR
+ pop_directory # BUILD_SRC_DIR/PROJECT
+
+ msg_success "'${PROJECT}' installation complete."
+}
+.endmacro # define_install_action
+.
+.macro define_install_cmake(meta, configuration, repository)
+. define my.meta = define_install_cmake.meta
+. define my.configuration = define_install_cmake.configuration
+. define my.repository = define_install_cmake.repository
+.
+. define_install_action(my.meta, my.configuration, my.repository, \
+ "cmake", "cmake --install .")
+.
+.endmacro # define_install_cmake
+.
+.macro define_install_gnu(meta, configuration, repository)
+. define my.meta = define_install_gnu.meta
+. define my.configuration = define_install_gnu.configuration
+. define my.repository = define_install_gnu.repository
+.
+. define_install_action(my.meta, my.configuration, my.repository, \
+ "gnu", "make install")
+.
+.endmacro # define_install_gnu
.
.macro define_build_cmake()
@@ -864,7 +983,7 @@ build_cmake()
if [[ "${DISPLAY_VERBOSE}" == "yes" ]]; then
VERBOSITY_CMAKE="-DCMAKE_VERBOSE_MAKEFILE=ON"
- VERBOSITY_MAKE="VERBOSE=1"
+ VERBOSITY_MAKE="--verbose"
fi
msg_heading "Preparing to build ${PROJECT}"
@@ -877,15 +996,16 @@ build_cmake()
# make
if [[ ${JOBS} -gt ${SEQUENTIAL} ]]; then
- make -j${JOBS} ${VERBOSITY_MAKE}
+ cmake --build . -j${JOBS} ${VERBOSITY_MAKE}
else
- make
+ cmake --build . ${VERBOSITY_MAKE}
fi
pop_directory # BUILD_OBJ_DIR
pop_directory # BUILD_SRC_DIR/PROJECT
msg_success "'${PROJECT}' built successfully."
}
+
.endmacro # define_build_cmake
.
.macro define_build_preset()
@@ -924,6 +1044,7 @@ build_preset()
pop_directory # BUILD_SRC_DIR/PROJECT
msg_success "'${PROJECT}' built successfully."
}
+
.endmacro # define_build_preset
.
.macro define_build_gnu()
@@ -967,6 +1088,7 @@ build_gnu()
pop_directory # BUILD_SRC_DIR/PROJECT
msg_success "'${PROJECT}' built successfully."
}
+
.endmacro # define_build_gnu
.
.macro define_build_boost()
@@ -1086,7 +1208,7 @@ $(my.c_indent)case ${OPTION} in
. abort "Expected hint_build value '$(_depend.hint_build)' not found for dependency '$(_depend.name)'."
. endif
.
-$(indent_column("(--build-$(_depend.name))", "BUILD_$(_depend.name)=\"yes\";;", my.column, my.o_indent))
+$(indent_column("(--build-$(option_name(_depend)))", "BUILD_$(option_name(_depend))=\"yes\";;", my.column, my.o_indent))
. endfor
.
. new options as _build_options
@@ -1116,7 +1238,7 @@ $(my.indent)CONFIGURE_OPTIONS=("$@")
. abort "Expected hint_build value '$(_depend.hint_build)' not found for dependency '$(_depend.name)'."
. endif
.
-$(my.indent)CONFIGURE_OPTIONS=("${CONFIGURE_OPTIONS[@]/--build-$(_depend.name)/}")
+$(my.indent)CONFIGURE_OPTIONS=("${CONFIGURE_OPTIONS[@]/--build-$(option_name(_depend))/}")
. endfor
.
. for _build_options.option as _option where is_defined_positive(_option, "sanitize")
@@ -1132,6 +1254,24 @@ $(my.indent)CONFIGURE_OPTIONS=("${CONFIGURE_OPTIONS[@]/$(option_symbol("short",
. endfor
. endnew
.
+. define my.canonical = my.meta->build(is_defined_positive(build, "canonical"))
+.
+. if (count(my.meta.build, build.method = "cmake") > 0)
+. if (my.canonical.method = "cmake")
+$(my.indent)CONFIGURE_OPTIONS_CMAKE=("${CONFIGURE_OPTIONS[@]}")
+. else
+$(my.indent)CONFIGURE_OPTIONS_CMAKE=()
+. endif
+. endif
+.
+. if (count(my.meta.build, build.method = "gnu") > 0)
+. if (my.canonical.method = "gnu")
+$(my.indent)CONFIGURE_OPTIONS_GNU=("${CONFIGURE_OPTIONS[@]}")
+. else
+$(my.indent)CONFIGURE_OPTIONS_GNU=()
+. endif
+. endif
+.
$(my.indent)msg_verbose "*** ARGUMENTS: ${CONFIGURE_OPTIONS_ORIGINAL[*]}"
$(my.indent)msg_verbose "*** SANITIZED: ${CONFIGURE_OPTIONS[*]}"
.
@@ -1280,33 +1420,36 @@ $(my.indent)msg_verbose "*** SANITIZED: ${CONFIGURE_OPTIONS[*]}"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${PREFIX}/lib"
fi
fi
-.
-. if (my.install.hint_options = "gnu")
-
- if [[ -n "${PREFIX}" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "--prefix=${PREFIX}" )
- fi
-. elsif (my.install.hint_options = "cmake")
+. if defined(my.meta->build(build.method = "cmake"))
if [[ -n "${PREFIX}" ]] && [[ -n "${CMAKE_INSTALL_PREFIX}" ]]; then
msg_error "Both PREFIX and CMAKE_INSTALL_PREFIX have been defined differently."
help
exit 1
- elif [[ -n "${PREFIX}" ]]; then
+ fi
+
+ if [[ -n "${PREFIX}" ]]; then
CMAKE_INSTALL_PREFIX="${PREFIX}"
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/-DCMAKE_INSTALL_PREFIX=*/}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DCMAKE_INSTALL_PREFIX=${PREFIX}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]/-DCMAKE_INSTALL_PREFIX=*/}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DCMAKE_INSTALL_PREFIX=${PREFIX}" )
fi
if [[ -n "${PREFIX}" ]] && [[ -n "${CMAKE_PREFIX_PATH}" ]] &&
[[ "${PREFIX}" != "${CMAKE_PREFIX_PATH}" ]]; then
CMAKE_PREFIX_PATH="${PREFIX}:${CMAKE_PREFIX_PATH}"
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/-DCMAKE_PREFIX_PATH=*/}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]/-DCMAKE_PREFIX_PATH=*/}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" )
elif [[ -n "${PREFIX}" ]]; then
CMAKE_INSTALL_PREFIX="${PREFIX}"
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/-DCMAKE_PREFIX_PATH=*/}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DCMAKE_PREFIX_PATH=${PREFIX}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]/-DCMAKE_PREFIX_PATH=*/}" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DCMAKE_PREFIX_PATH=${PREFIX}" )
+ fi
+. endif
+.
+. if defined(my.meta->build(build.method = "gnu"))
+
+ if [[ -n "${PREFIX}" ]]; then
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]}" "--prefix=${PREFIX}" )
fi
. endif
@@ -1406,46 +1549,49 @@ $(my.indent)msg_verbose "*** SANITIZED: ${CONFIGURE_OPTIONS[*]}"
msg_verbose "CXXFLAGS modified to '${CXXFLAGS}'"
fi
fi
-
-. if (my.install.hint_options = "gnu")
+.
+. if defined(my.meta->build(build.method = "gnu"))
+
# Specify or remove --enable-ndebug for gnu toolchain on release
if [[ "${BUILD_CONFIG}" == "debug" ]]; then
- CONFIGURE_OPTIONS=("${CONFIGURE_OPTIONS[@]/--enable-ndebug/}")
+ CONFIGURE_OPTIONS_GNU=("${CONFIGURE_OPTIONS_GNU[@]/--enable-ndebug/}")
elif [[ "${BUILD_CONFIG}" == "release" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "--enable-ndebug" )
+ CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS_GNU[@]}" "--enable-ndebug" )
fi
-. elsif (my.install.hint_options = "cmake")
+. endif
+.
+. if defined(my.meta->build(build.method = "cmake"))
+
# Specify cmake build
if [[ "${BUILD_CONFIG}" == "debug" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DCMAKE_BUILD_TYPE=Debug" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DCMAKE_BUILD_TYPE=Debug" )
elif [[ "${BUILD_CONFIG}" == "release" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DCMAKE_BUILD_TYPE=Release" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DCMAKE_BUILD_TYPE=Release" )
fi
-. else
-. abort "Unexpected hint_options: '$(my.install.hint_options)'"
. endif
# translate BUILD_LINK to appropriate arguments
if [[ -n "${BUILD_LINK}" ]]; then
-. if (my.install.hint_options = "gnu")
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/--disable-shared=*}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/--enable-shared=*}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/--disable-static=*}" )
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/--enable-static=*}" )
+. if defined(my.meta->build(build.method = "gnu"))
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]/--disable-shared=*}" )
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]/--enable-shared=*}" )
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]/--disable-static=*}" )
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]/--enable-static=*}" )
if [[ "${BUILD_LINK}" == "dynamic" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "--enable-shared" "--disable-static" )
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]}" "--enable-shared" "--disable-static" )
else
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "--disable-shared" "--enable-static" )
+ CONFIGURE_OPTIONS_GNU=( "${CONFIGURE_OPTIONS_GNU[@]}" "--disable-shared" "--enable-static" )
fi
+. endif
.
-. elsif (my.install.hint_options = "cmake")
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]/-DBUILD_SHARED_LIBS=*}" )
+. if defined(my.meta->build(build.method = "cmake"))
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]/-DBUILD_SHARED_LIBS=*}" )
if [[ "${BUILD_LINK}" == "dynamic" ]]; then
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DBUILD_SHARED_LIBS=ON" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DBUILD_SHARED_LIBS=ON" )
else
- CONFIGURE_OPTIONS=( "${CONFIGURE_OPTIONS[@]}" "-DBUILD_SHARED_LIBS=OFF" )
+ CONFIGURE_OPTIONS_CMAKE=( "${CONFIGURE_OPTIONS_CMAKE[@]}" "-DBUILD_SHARED_LIBS=OFF" )
fi
. endif
fi
@@ -1468,7 +1614,7 @@ $(my.indent)msg_verbose "*** SANITIZED: ${CONFIGURE_OPTIONS[*]}"
.
. if (my.hint_root | my.hint_with)
- if [[ -n "${BUILD_$(_depend.name:c)}" ]]; then
+ if [[ -n "${BUILD_$(option_name(_depend))}" ]]; then
. if (my.hint_root)
export $(_depend.name:upper)_ROOT="${PREFIX}"
. endif
@@ -1480,16 +1626,28 @@ $(my.indent)msg_verbose "*** SANITIZED: ${CONFIGURE_OPTIONS[*]}"
. endif
. endfor
+. if defined(my.meta->build(build.method = "cmake"))
+. remap_array_variable("CONFIGURE_OPTIONS_CMAKE")
+. endif
+. if defined(my.meta->build(build.method = "gnu"))
+. remap_array_variable("CONFIGURE_OPTIONS_GNU")
+. endif
+.
+.endmacro # define_sanitize_input
+.
+.macro remap_array_variable(name)
+. define my.name = remap_array_variable.name
+.
+
REMAP=()
- for argument in "${CONFIGURE_OPTIONS[@]}"; do
+ for argument in "${$(my.name)[@]}"; do
if [[ -n "${argument}" ]]; then
REMAP+=( "${argument}" )
fi
done
- CONFIGURE_OPTIONS=( "${REMAP[@]}" )
+ $(my.name)=( "${REMAP[@]}" )
unset REMAP
-.
-.endmacro # define_sanitize_input
+.endmacro # remp_array_variable
.
.macro define_main(meta, configuration, repository, install)
. define my.meta = define_main.meta
@@ -1532,13 +1690,14 @@ main()
.
. for my.install.dependency as _depend
. define my.found_source = 0
+. define my.oname = option_name(_depend)
. define my.vname = "$(_depend.name:c)"
. define my.priority_source = ""
. define my.indent = my.step
.
. if (is_defined_positive(_depend, "conditional"))
-$(my.indent)if [[ ${BUILD_$(my.vname)} == "yes" ]]; then
+$(my.indent)if [[ ${BUILD_$(my.oname)} == "yes" ]]; then
. my.indent = "$(my.step)$(my.indent)"
. endif
.
@@ -1583,41 +1742,41 @@ $(my.indent)export CPPFLAGS="${CPPFLAGS} ${$(my.vname)_FLAGS[@]}"
.
. if (my.active_build.method = "gnu")
. require(my.active_build, "build", "filepath")
-$(my.indent)build_gnu "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS[@]}"
+$(my.indent)build_gnu "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS_GNU[@]}"
. if last()
$(my.indent)if ! [[ "${BUILD_SKIP_TESTS}" == "yes" ]]; then
- $(my.indent)test_make "$(_depend.name)" "check" "${PARALLEL}"
+ $(my.indent)test_gnu "$(_depend.name)" "${PARALLEL}"
$(my.indent)fi
. endif
-$(my.indent)install_make "$(_depend.name)"
+$(my.indent)install_gnu "$(_depend.name)"
$(my.indent)if [[ "${BUILD_POST_INSTALL_CLEAN}" == "yes" ]]; then
- $(my.indent)clean_make "$(_depend.name)"
+ $(my.indent)clean_gnu "$(_depend.name)"
$(my.indent)fi
.
. elsif (my.active_build.method = "cmake")
. require(my.active_build, "build", "filepath")
-$(my.indent)build_cmake "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS[@]}"
+$(my.indent)build_cmake "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS_CMAKE[@]}"
. if last()
$(my.indent)if ! [[ "${BUILD_SKIP_TESTS}" == "yes" ]]; then
- $(my.indent)test_make "$(_depend.name)" "test" "${PARALLEL}"
+ $(my.indent)test_cmake "$(_depend.name)" "${PARALLEL}"
$(my.indent)fi
. endif
-$(my.indent)install_make "$(_depend.name)"
+$(my.indent)install_cmake "$(_depend.name)"
$(my.indent)if [[ "${BUILD_POST_INSTALL_CLEAN}" == "yes" ]]; then
- $(my.indent)clean_make "$(_depend.name)"
+ $(my.indent)clean_cmake "$(_depend.name)"
$(my.indent)fi
.
. elsif (my.active_build.method = "preset")
. require(my.active_build, "build", "filepath")
-$(my.indent)build_preset "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS[@]}"
+$(my.indent)build_preset "$(_depend.name)" "$(my.active_build.filepath)" "${PARALLEL}" "${$(my.vname)_OPTIONS[@]}" "${CONFIGURE_OPTIONS_CMAKE[@]}"
. if last()
$(my.indent)if ! [[ "${BUILD_SKIP_TESTS}" == "yes" ]]; then
- $(my.indent)test_make "$(_depend.name)" "test" "${PARALLEL}"
+ $(my.indent)test_cmake "$(_depend.name)" "test" "${PARALLEL}"
$(my.indent)fi
. endif
-$(my.indent)install_make "$(_depend.name)"
+$(my.indent)install_cmake "$(_depend.name)"
$(my.indent)if [[ "${BUILD_POST_INSTALL_CLEAN}" == "yes" ]]; then
- $(my.indent)clean_make "$(_depend.name)"
+ $(my.indent)clean_cmake "$(_depend.name)"
$(my.indent)fi
.
. elsif (my.active_build.method = "boost_build")
diff --git a/templates/src/include.hpp.gsl b/templates/src/include.hpp.gsl
index 2d129796..9a71df6c 100644
--- a/templates/src/include.hpp.gsl
+++ b/templates/src/include.hpp.gsl
@@ -78,65 +78,6 @@ endfunction
###############################################################################
# Functions
###############################################################################
-function discover_files(files, meta, path)
- define my.files = discover_files.files
- define my.meta = discover_files.meta
- define my.path = discover_files.path
-
- # meta presumed structure:
- #
- #
- #
- #
-
- define my.directory = directory.open(my.path)?
-
- if !defined(my.directory)
- abort "Directory open failure: $(error_text)"
- endif
-
- my.files.path = my.directory.path
- my.files.name = my.directory.name
- my.files.query = my.path
-
- for my.directory.directory as _subdirectory
- new my.files.directory as _directory
- discover_files(_directory, my.meta, "$(_subdirectory.path)$(_subdirectory.name)")
- endnew
- endfor
-
- for my.directory.file as _file by _file.name \
- where is_targeted_file(_file, my.meta)
-
- new my.files.file as _active_file
- _active_file.name = _file.name
- _active_file.path = _file.path
- _active_file.size = _file.size
- _active_file.time = _file.time
- _active_file.date = _file.date
- endnew
- endfor
-endfunction
-
-function is_targeted_file(file, meta)
- define my.file = is_targeted_file.file
- define my.meta = is_targeted_file.meta
-
- define my.filterless = (count(my.meta.match) = 0)
-
- if my.filterless
- return 1
- endif
-
- for my.meta.match as _filter where defined(_filter.suffix)
- if ends_with(my.file.name, _filter.suffix)
- return 1
- endif
- endfor
-
- return 0
-endfunction
-
function short_name(host)
define my.host = short_name.host
diff --git a/templates/src/version.hpp.gsl b/templates/src/version.hpp.gsl
new file mode 100644
index 00000000..1c58c75f
--- /dev/null
+++ b/templates/src/version.hpp.gsl
@@ -0,0 +1,145 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate version.hpp.
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/cpp-output.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_version_hpp(configuration)
+ define my.configuration = generate_version_hpp.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ define my.project_path_suffix = my.template.outpath
+
+ for my.configuration.repository as _repository
+ require(_repository, "repository", "name")
+ define my.short_name = short_name(_repository)
+
+ # ASSUMPTION: currently assumes 1 path per repository with relative path provided
+ # by template. generalization for multiple libraries needs path pulled from library.
+ define my.output_path = path_append(\
+ my.configuration->templates.resultpath, \
+ path_append(my.path_prefix, \
+ path_append(_repository.name, \
+ path_append(my.project_path_suffix, my.short_name))))
+
+ create_directory(my.output_path)
+
+ if !(starts_with(_repository.name, "libbitcoin-"))
+ abort "Repository name does not start with 'libbitocoin-': '$(_repository.name)'"
+ endif
+
+ for _repository.library as _library where starts_with(_library.name, "libbitcoin-")
+ define my.filename = "version.hpp"
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ emit_version_hpp(my.short_name, _library, _repository, my.template,\
+ my.configuration)
+
+ close
+ endfor
+ endfor
+
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+function short_name(host)
+ define my.host = short_name.host
+
+ if !defined(my.host.name)
+ abort "Missing 'name' property."
+ endif
+
+ if !starts_with(my.host.name, "libbitcoin-")
+ abort "Library '$(my.host.name)' does not start with 'libbitcoin-'."
+ endif
+
+ return string.substr(my.host.name, 11, string.length(my.host.name))
+endfunction
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_version_hpp(name, library, repository, meta, configuration)
+. define my.name = emit_version_hpp.name
+. define my.library = emit_version_hpp.library
+. define my.repository = emit_version_hpp.repository
+. define my.meta = emit_version_hpp.meta
+. define my.configuration = emit_version_hpp.configuration
+.
+. define my.reposymbol = "$(my.repository.name:c,upper)"
+. if !defined(my.repository->version)
+. abort "Repository lacks 'version' element."
+. endif
+.
+. define my.version = my.repository->version
+.
+. if !defined(my.version.major) | !defined(my.version.minor)
+. abort "Repository 'version' lacks 'major' or 'minor'."
+. endif
+.
+. if !defined(my.version.patch)
+. my.version.patch = "0"
+. endif
+.
+. copyleft(my.library.name)
+.
+#ifndef $(my.reposymbol)_VERSION_HPP
+#define $(my.reposymbol)_VERSION_HPP
+
+/**
+ * The semantic version of this repository as: [major].[minor].[patch]
+ * For interpretation of the versioning scheme see: http://semver.org
+ */
+
+#define $(my.reposymbol)_VERSION "$(my.version.major).$(my.version.minor).$(my.version.patch)"
+#define $(my.reposymbol)_MAJOR_VERSION $(my.version.major)
+#define $(my.reposymbol)_MINOR_VERSION $(my.version.minor)
+#define $(my.reposymbol)_PATCH_VERSION $(my.version.patch)
+
+#endif
+.
+.endmacro # emit_version_hpp
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_version_hpp(configuration)
+
+.endtemplate
diff --git a/templates/src/version.hpp.in.gsl b/templates/src/version.hpp.in.gsl
new file mode 100644
index 00000000..1454fc5e
--- /dev/null
+++ b/templates/src/version.hpp.in.gsl
@@ -0,0 +1,144 @@
+.template 0
+###############################################################################
+# Copyright (c) 2014-2026 libbitcoin developers (see COPYING).
+#
+# GSL generate version.hpp.
+#
+# This is a code generator built using the iMatix GSL code generation
+# language. See https://github.com/imatix/gsl for details.
+###############################################################################
+
+# Note: expected context root libbitcoin-build/process directory
+[gsl].ignorecase = 0
+
+gsl from "../library/math.gsl"
+gsl from "../library/string.gsl"
+gsl from "../lib/xml.gsl"
+gsl from "../lib/debug.gsl"
+gsl from "../lib/filesystem.gsl"
+gsl from "../lib/output.gsl"
+gsl from "../lib/cpp-output.gsl"
+
+###############################################################################
+# Generation
+###############################################################################
+function generate_version_hpp_in(configuration)
+ define my.configuration = generate_version_hpp_in.configuration
+ require(my.configuration->templates, "templates", "resultpath")
+
+ define my.template = my.configuration->templates->template(.name = "$(script)")
+
+ if !defined(my.template)
+ abort "Generator configuration missing."
+ endif
+
+ require(my.template, "template", "outpath")
+
+ define my.project_path_suffix = my.template.outpath
+
+ for my.configuration.repository as _repository
+ require(_repository, "repository", "name")
+ define my.short_name = short_name(_repository)
+
+ # ASSUMPTION: currently assumes 1 path per repository with relative path provided
+ # by template. generalization for multiple libraries needs path pulled from library.
+ define my.output_path = path_append(\
+ my.configuration->templates.resultpath, \
+ path_append(my.path_prefix, \
+ path_append(_repository.name, \
+ path_append(my.project_path_suffix, my.short_name))))
+
+ create_directory(my.output_path)
+
+ if !(starts_with(_repository.name, "libbitcoin-"))
+ abort "Repository name does not start with 'libbitocoin-': '$(_repository.name)'"
+ endif
+
+ for _repository.library as _library where starts_with(_library.name, "libbitcoin-")
+ define my.filename = "version.hpp.in"
+ define my.out_file = path_append(my.output_path, my.filename)
+
+ notify(my.out_file)
+ output(my.out_file)
+
+ emit_version_hpp_in(my.short_name, _library, _repository, my.template,\
+ my.configuration)
+
+ close
+ endfor
+ endfor
+
+endfunction
+
+###############################################################################
+# Functions
+###############################################################################
+function short_name(host)
+ define my.host = short_name.host
+
+ if !defined(my.host.name)
+ abort "Missing 'name' property."
+ endif
+
+ if !starts_with(my.host.name, "libbitcoin-")
+ abort "Library '$(my.host.name)' does not start with 'libbitcoin-'."
+ endif
+
+ return string.substr(my.host.name, 11, string.length(my.host.name))
+endfunction
+
+###############################################################################
+# Generation
+###############################################################################
+.endtemplate
+.template 1
+.
+.macro emit_version_hpp_in(name, library, repository, meta, configuration)
+. define my.name = emit_version_hpp_in.name
+. define my.library = emit_version_hpp_in.library
+. define my.repository = emit_version_hpp_in.repository
+. define my.meta = emit_version_hpp_in.meta
+. define my.configuration = emit_version_hpp_in.configuration
+.
+. define my.reposymbol = "$(my.repository.name:c,upper)"
+. if !defined(my.repository->version)
+. abort "Repository lacks 'version' element."
+. endif
+.
+. define my.version = my.repository->version
+.
+. if !defined(my.version.major) | !defined(my.version.minor)
+. abort "Repository 'version' lacks 'major' or 'minor'."
+. endif
+.
+. copyleft(my.library.name)
+.
+#ifndef $(my.reposymbol)_VERSION_HPP
+#define $(my.reposymbol)_VERSION_HPP
+
+/**
+ * The semantic version of this repository as: [major].[minor].[patch]
+ * For interpretation of the versioning scheme see: http://semver.org
+ */
+
+#define $(my.reposymbol)_VERSION "@LIBBITCOIN_VERSION_MAJOR@.@LIBBITCOIN_VERSION_MINOR@.@LIBBITCOIN_VERSION_PATCH@"
+#define $(my.reposymbol)_MAJOR_VERSION @LIBBITCOIN_VERSION_MAJOR@
+#define $(my.reposymbol)_MINOR_VERSION @LIBBITCOIN_VERSION_MINOR@
+#define $(my.reposymbol)_PATCH_VERSION @LIBBITCOIN_VERSION_PATCH@
+#define $(my.reposymbol)_COMMIT_HASH "@GIT_COMMIT_HASH@"
+#define $(my.reposymbol)_REPOSITORY_URL "@GIT_ORIGIN_URL@"
+#define $(my.reposymbol)_IS_DIRTY @GIT_DIRTY@
+
+#endif
+.
+.endmacro # emit_version_hpp_in
+.
+.endtemplate
+.template 0
+###############################################################################
+# Execution
+###############################################################################
+
+generate_version_hpp_in(configuration)
+
+.endtemplate
diff --git a/version4.xml b/version4.xml
index ad976bfd..63151a3f 100644
--- a/version4.xml
+++ b/version4.xml
@@ -2,18 +2,26 @@
+
+
-
+
+
+
+
+
+
+
+
+
+
@@ -49,7 +67,8 @@
-
+
+
-
+
-
+
+
+
+
@@ -165,12 +190,15 @@
-
+
-
+
+
+
+
+
+
@@ -402,15 +430,20 @@
+
+
-
+
+
+
@@ -418,6 +451,11 @@
+
@@ -446,16 +484,23 @@
-
+
-
+
+
-
+
+
+
+
@@ -694,18 +739,28 @@
+
+
-
+
+
+
+
@@ -725,11 +780,17 @@
-
+
-
+
+
+
+
@@ -756,11 +817,17 @@
-
-
+
+
+
+
+
+
@@ -988,18 +1055,26 @@
+
+
-
+
+
+
+
+
+
@@ -1020,11 +1095,17 @@
-
+
-
+
+
+
+
@@ -1257,18 +1338,26 @@
+
+
-
+
+
+
+
+
+
@@ -1286,13 +1375,19 @@
-
+
-
+
-
+
+
+
+
@@ -1319,12 +1414,19 @@
-
+
-
+
+
+
+
+
+
+
+
+
@@ -1678,7 +1780,7 @@
-
+
@@ -1797,7 +1899,44 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1813,12 +1952,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
@@ -2191,6 +2363,40 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
+
@@ -2234,9 +2441,9 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
-
+
-
+
@@ -2262,9 +2469,9 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
-
+
-
+
@@ -2283,8 +2490,8 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
-
-
+
+
@@ -2341,14 +2548,23 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
+ path="src"
+ outpath="include/bitcoin"
+ filterpath="bitcoin/">
-
-
+
+
+
+
+
+
+
@@ -2419,5 +2635,99 @@ g and optimizations for size." hidden="false" display="*nix/GNU/Release/Static/S
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+