Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions src/tools/brotli.jam
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright (c) 2025 Mohammad Nejati
#
# Use, modification and distribution is subject to the Boost Software
# License Version 1.0. (See accompanying file LICENSE.txt or
# https://www.bfgroup.xyz/b2/LICENSE.txt)

# Supports the brotli library
#
# After 'using brotli', the following targets are available:
#
# /brotli//brotlicommon -- The brotli common library
# /brotli//brotlidec -- The brotli decoder library
# /brotli//brotlienc -- The brotli encoder library

import project ;
import ac ;
import errors ;
import feature ;
import "class" : new ;
import targets ;
import path ;
import modules ;
import indirect ;
import property ;
import property-set ;
import args ;

header = brotli/decode.h ;
brotlicommon_names = brotlicommon libbrotlicommon ;
brotlidec_names = brotlidec libbrotlidec ;
brotlienc_names = brotlienc libbrotlienc ;

library-id = 0 ;

.debug = [ args.get-arg debug-configuration ] ;

# Initializes the brotli library.
#
# Options for configuring brotli::
#
# <search>
# The directory containing the brotli binaries.
# <brotlicommon-name>
# Overrides the default name of brotlicommon library.
# <brotlidec-name>
# Overrides the default name of brotlidec library.
# <brotlienc-name>
# Overrides the default name of brotlienc library.
# <include>
# The directory containing the brotli headers.
# <dll-path>
# Extra directories to add to library search paths of consumers during
# runtime (multiple instances are allowed).
#
# If none of these options is specified, then the environmental
# variables BROTLI_LIBRARY_PATH, BROTLI_NAME, and BROTLI_INCLUDE will
# be used instead.
#
# Examples::
#
# # Find brotli in the default system location
# using brotli ;
# # Find brotli in /usr/local
# using brotli : 1.1.0
# : <include>/usr/local/include <search>/usr/local/lib ;
#
rule init (
version ?
# (currently ignored)

: options *
# A list of the options to use

: requirements *
# The requirements for the target

: is-default ?
)
{
local caller = [ project.current ] ;

if ! $(.initialized)
{
.initialized = true ;

project.initialize $(__name__) ;
.project = [ project.current ] ;
project brotli ;
}

local library-path = [ feature.get-values <search> : $(options) ] ;
local include-path = [ feature.get-values <include> : $(options) ] ;
local brotlicommon-name = [ feature.get-values <brotlicommon-name> : $(options) ] ;
local brotlidec-name = [ feature.get-values <brotlidec-name> : $(options) ] ;
local brotlienc-name = [ feature.get-values <brotlienc-name> : $(options) ] ;
local dll-paths = [ property.select <dll-path> : $(options) ] ;

if ! $(options)
{
is-default = true ;
}

condition = [ property-set.create $(requirements) ] ;
condition = [ property-set.create [ $(condition).base ] ] ;

if $(.configured.$(condition))
{
if $(is-default)
{
if $(.debug)
{
ECHO "notice: [brotli] brotli is already configured" ;
}
}
else
{
errors.user-error "brotli is already configured" ;
}
return ;
}
else
{
if $(.debug)
{
ECHO "notice: [brotli] Using pre-installed library" ;
if $(condition)
{
ECHO "notice: [brotli] Condition" [ $(condition).raw ] ;
}
}

local brotlicommon = [ new ac-library brotlicommon : $(.project) : $(condition) :
$(include-path) : $(library-path) : $(brotlicommon-name) ] ;
$(brotlicommon).set-header $(header) ;
$(brotlicommon).set-default-names $(brotlicommon_names) ;
$(brotlicommon).add-usage-requirements $(dll-paths) ;

local brotlidec = [ new ac-library brotlidec : $(.project) : $(condition) :
$(include-path) : $(library-path) : $(brotlidec-name) ] ;
$(brotlidec).set-header $(header) ;
$(brotlidec).set-default-names $(brotlidec_names) ;
$(brotlidec).add-usage-requirements $(dll-paths) ;

local brotlienc = [ new ac-library brotlienc : $(.project) : $(condition) :
$(include-path) : $(library-path) : $(brotlienc-name) ] ;
$(brotlienc).set-header $(header) ;
$(brotlienc).set-default-names $(brotlienc_names) ;
$(brotlienc).add-usage-requirements $(dll-paths) ;

targets.main-target-alternative $(brotlicommon) ;
targets.main-target-alternative $(brotlidec) ;
targets.main-target-alternative $(brotlienc) ;
}
.configured.$(condition) = true ;
}
120 changes: 120 additions & 0 deletions test/libbrotli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3

# Copy-paste-modify from libzstd.py
# Copyright (C) 2013 Steven Watanabe
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at
# https://www.bfgroup.xyz/b2/LICENSE.txt)

import BoostBuild
import MockToolset

t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0)

MockToolset.create(t)

# Generic definitions that aren't configuration specific
common_stuff = '''
source_file('test.cpp', 'test.cpp')
source_file('main.cpp', 'int main() {}')
source_file('brotli/decode.h.cpp', '#include <brotli/decode.h>\\n')
action('-c -x c++ $main.cpp -o $main.o')
'''
t.write('test.cpp', 'test.cpp')

for lib in ('brotlicommon', 'brotlidec', 'brotlienc'):

# Default initialization - static library
t.rm('bin')
t.write("Jamroot.jam", """
path-constant here : . ;
using brotli ;
exe test : test.cpp /brotli//%(lib)s : : <link>static <link>shared ;
""" % {'lib': lib})

MockToolset.set_expected(t, common_stuff + '''
action('$main.o --static-lib=%(lib)s -o $config.exe')
action('-c -x c++ $brotli/decode.h.cpp -o $brotli/decode.h.o')
action('-c -x c++ $test.cpp -o $test.o')
action('$test.o --static-lib=%(lib)s -o $test')
''' % {'lib': lib})
t.run_build_system()
t.expect_addition('bin/mock/debug/test.exe')
t.expect_addition('bin/mock/debug/link-static/test.exe')

# Default initialization - shared library
t.rm('bin')
t.write("Jamroot.jam", """
path-constant here : . ;
using brotli ;
exe test : test.cpp /brotli//%(lib)s : : <link>static <link>shared ;
""" % {'lib': lib})

MockToolset.set_expected(t, common_stuff + '''
action('$main.o --shared-lib=%(lib)s -o $config.exe')
action('-c -x c++ $brotli/decode.h.cpp -o $brotli/decode.h.o')
action('-c -x c++ $test.cpp -o $test.o')
action('$test.o --shared-lib=%(lib)s -o $test')
''' % {'lib': lib})
t.run_build_system()
t.expect_addition('bin/mock/debug/test.exe')
t.expect_addition('bin/mock/debug/link-static/test.exe')

# Initialization in explicit location - static library
t.rm('bin')
t.write("Jamroot.jam", """
path-constant here : . ;
using brotli : : <%(lib)s-name>my%(lib)s <include>$(here)/brotli <search>$(here)/brotli ;
exe test : test.cpp /brotli//%(lib)s : : <link>static <link>shared ;
""" % {'lib': lib})

t.write('brotli/brotli/decode.h', 'brotli')

MockToolset.set_expected(t, common_stuff + '''
action('$main.o -L./brotli --static-lib=my%(lib)s -o $config.exe')
action('-c -x c++ $test.cpp -I./brotli -o $test.o')
action('$test.o -L./brotli --static-lib=my%(lib)s -o $test')
''' % {'lib': lib})
t.run_build_system()
t.expect_addition('bin/mock/debug/test.exe')
t.expect_addition('bin/mock/debug/link-static/test.exe')

# Initialization in explicit location - shared library
t.rm('bin')
t.write("Jamroot.jam", """
path-constant here : . ;
using brotli : : <%(lib)s-name>my%(lib)s <include>$(here)/brotli <search>$(here)/brotli ;
exe test : test.cpp /brotli//%(lib)s : : <link>static <link>shared ;
""" % {'lib': lib})

MockToolset.set_expected(t, common_stuff + '''
action('$main.o -L./brotli --shared-lib=my%(lib)s -o $config.exe')
action('-c -x c++ $test.cpp -I./brotli -o $test.o')
action('$test.o -L./brotli --shared-lib=my%(lib)s -o $test')
''' % {'lib': lib})
t.run_build_system()
t.expect_addition('bin/mock/debug/test.exe')
t.expect_addition('bin/mock/debug/link-static/test.exe')

# Initialization in explicit location - both static and shared libraries
t.rm('bin')
t.write("Jamroot.jam", """
path-constant here : . ;
using brotli : : <%(lib)s-name>my%(lib)s <include>$(here)/brotli <search>$(here)/brotli ;
exe test : test.cpp /brotli//%(lib)s
: <link>shared:<define>SHARED : <link>static <link>shared ;
""" % {'lib': lib})

MockToolset.set_expected(t, common_stuff + '''
action('$main.o -L./brotli --static-lib=my%(lib)s -o $config.exe')
action('$main.o -L./brotli --shared-lib=my%(lib)s -o $config.exe')
action('-c -x c++ $test.cpp -I./brotli -o $test-static.o')
action('-c -x c++ $test.cpp -I./brotli -DSHARED -o $test-shared.o')
action('$test-static.o -L./brotli --static-lib=my%(lib)s -o $test')
action('$test-shared.o -L./brotli --shared-lib=my%(lib)s -o $test')
''' % {'lib': lib})
t.run_build_system()
t.expect_addition('bin/mock/debug/test.exe')
t.expect_addition('bin/mock/debug/link-static/test.exe')

t.cleanup()
1 change: 1 addition & 0 deletions test/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ def reorder_tests(tests, first_test):
"inline",
"install_build_no",
"lang_asm",
"libbrotli",
"lib_source_property",
"lib_zlib",
"libjpeg",
Expand Down
Loading