Skip to content

Commit b34abb4

Browse files
Merge branch 'dev' into feature/aks-fix-windows-gcs
2 parents 69e60b7 + b776d8b commit b34abb4

File tree

2 files changed

+328
-3
lines changed

2 files changed

+328
-3
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2020 Google
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
"""Standalone script to build desktops apps with Firebase.
17+
18+
Standalone self-sufficient (no external dependencies) python script that can
19+
ease building desktop apps with Firebase, by either using the C++ source
20+
(firebase-cpp-sdk github repo) or the prebuilt release Firebase libraries.
21+
22+
Note that this script works with only Python3 (3.6+).
23+
Also note, that since this script runs a cmake configure step, it is advised to
24+
run it with a fresh clean build directory.
25+
26+
Known side effects:
27+
If building against Firebase cpp source, this script might checkout a specific
28+
branch on github containing vcpkg. This will not be required once vcpkg is in
29+
the main branch.
30+
31+
Example usage:
32+
Let's say we want to build the quickstart cpp example for Firebase database.
33+
As specified above, there are 2 options - build against the Firebase source or
34+
prebuilt Firebase libraries.
35+
36+
# Build against the Firebase cpp sdk source
37+
python3 scripts/build_desktop_app_with_firebase.py
38+
--app_dir ~/quickstart-cpp/database/testapp
39+
--sdk_dir .
40+
--build_dir build_source
41+
42+
(or)
43+
44+
# Build against the prebuilt released Firebase libraries
45+
python3 scripts/build_desktop_app_with_firebase.py
46+
--app_dir ~/quickstart-cpp/database/testapp
47+
--sdk_dir ~/prebuilt/firebase_cpp_sdk_6.15.1/
48+
--build_dir build_prebuilt
49+
50+
# If the script ran successfully, it will print the path to the build directory.
51+
# The output looks like the following,
52+
Build successful!
53+
Please find your executables in build directory:
54+
/Users/<user>/quickstart-cpp/database/testapp/build_source
55+
56+
# Running the built example
57+
$ ./Users/<user>/quickstart-cpp/database/testapp/build_source/desktop_testapp
58+
"""
59+
import argparse
60+
import os
61+
import platform
62+
import subprocess
63+
import sys
64+
65+
66+
def is_path_valid_for_cmake(path):
67+
"""Check if specified path is setup for cmake."""
68+
return os.path.exists(os.path.join(path, 'CMakeLists.txt'))
69+
70+
71+
def is_sdk_path_source(sdk_dir):
72+
"""Validate if Firebase sdk dir is Firebase cpp source dir."""
73+
# Not the most reliable way to detect if the sdk path is source or prebuilt
74+
# but should work for our purpose.
75+
return os.path.exists(os.path.join(sdk_dir, 'build_tools'))
76+
77+
78+
def validate_prebuilt_args(arch, config):
79+
"""Validate cmd line args for build with prebuilt libraries."""
80+
# Some options are not available when using prebuilt libraries.
81+
if platform.system() == 'Darwin':
82+
if arch == 'x86' or config == 'Debug':
83+
raise ValueError('Prebuilt mac Firebase libraries are built for x64 and '
84+
'Release mode only. '
85+
'Please fix the command line arguments and try again')
86+
87+
if platform.system() == 'Linux':
88+
if config == 'Debug':
89+
raise ValueError('Prebuilt linux Firebase libraries are built with '
90+
'Release mode only. Please fix the --config command '
91+
'line argument and try again.')
92+
93+
94+
def get_vcpkg_triplet(arch, msvc_runtime_library='static'):
95+
"""Get vcpkg target triplet (platform definition).
96+
97+
Args:
98+
arch (str): Architecture (eg: 'x86', 'x64').
99+
msvc_runtime_library (str): Runtime library for MSVC.
100+
(eg: 'static', 'dynamic').
101+
102+
Raises:
103+
ValueError: If current OS is not win, mac or linux.
104+
105+
Returns:
106+
(str): Triplet name.
107+
Eg: "x64-windows-static".
108+
"""
109+
triplet_name = [arch]
110+
if platform.system() == 'Windows':
111+
triplet_name.append('windows')
112+
triplet_name.append('static')
113+
if msvc_runtime_library == 'dynamic':
114+
triplet_name.append('md')
115+
elif platform.system() == 'Darwin':
116+
triplet_name.append('osx')
117+
elif platform.system() == 'Linux':
118+
triplet_name.append('linux')
119+
else:
120+
raise ValueError('Unsupported platform. This function works only on '
121+
'Windows, Linux or Mac platforms.')
122+
123+
triplet_name = '-'.join(triplet_name)
124+
print('Using vcpkg triplet: {0}'.format(triplet_name))
125+
return triplet_name
126+
127+
128+
def build_source_vcpkg_dependencies(sdk_source_dir, arch, msvc_runtime_library):
129+
"""Build C++ dependencies for Firebase source SDK using vcpkg.
130+
131+
Args:
132+
sdk_source_dir (str): Path to Firebase C++ source directory.
133+
arch (str): Platform Architecture (eg: 'x64').
134+
msvc_runtime_library (str): Runtime library for MSVC.
135+
(eg: 'static', 'dynamic').
136+
"""
137+
# TODO(b/174141707): Remove this once dev branch of firebase-cpp-sdk repo has
138+
# been merged onto main branch. This is required because vcpkg lives only in
139+
# dev branch currently.
140+
subprocess.run(['git', 'checkout', 'dev'],
141+
cwd=sdk_source_dir, check=True)
142+
subprocess.run(['git', 'pull'], cwd=sdk_source_dir, check=True)
143+
144+
# sys.executable should point to the python bin running this script. We use
145+
# the same executable to execute these subprocess python scripts.
146+
subprocess.run([sys.executable, 'scripts/gha/install_prereqs_desktop.py'],
147+
cwd=sdk_source_dir, check=True)
148+
subprocess.run([sys.executable, 'scripts/gha/build_desktop.py',
149+
'--arch', arch,
150+
'--msvc_runtime_library', msvc_runtime_library,
151+
'--vcpkg_step_only'], cwd=sdk_source_dir, check=True)
152+
153+
154+
def build_app_with_source(app_dir, sdk_source_dir, build_dir, arch,
155+
msvc_runtime_library='static', config=None,
156+
target_format=None):
157+
"""Build desktop app directly against the Firebase C++ SDK source.
158+
159+
Since this involves a cmake configure, it is advised to run this on a clean
160+
build directory.
161+
162+
Args:
163+
app_dir (str): Path to directory containing application's CMakeLists.txt.
164+
sdk_source_dir (str): Path to Firebase C++ SDK source directory.
165+
(root of firebase-cpp-sdk github repo).
166+
build_dir (str): Output build directory.
167+
arch (str): Platform Architecture (example: 'x64').
168+
msvc_runtime_library (str): Runtime library for MSVC.
169+
(eg: 'static', 'dynamic').
170+
config (str): Release/Debug config.
171+
If it's not specified, cmake's default is used (most likely Debug).
172+
target_format (str): If specified, build for this target format.
173+
('frameworks' or 'libraries').
174+
"""
175+
# Cmake configure.
176+
cmd = ['cmake', '-S', '.', '-B', build_dir]
177+
cmd.append('-DFIREBASE_CPP_SDK_DIR={0}'.format(sdk_source_dir))
178+
179+
# If generator is not specified, default for platform is used by cmake, else
180+
# use the specified value.
181+
if config:
182+
cmd.append('-DCMAKE_BUILD_TYPE={0}'.format(config))
183+
# workaround, absl doesn't build without tests enabled.
184+
cmd.append('-DBUILD_TESTING=off')
185+
186+
if platform.system() == 'Linux' and arch == 'x86':
187+
# Use a separate cmake toolchain for cross compiling linux x86 builds.
188+
vcpkg_toolchain_file_path = os.path.join(sdk_source_dir, 'external',
189+
'vcpkg', 'scripts',
190+
'buildsystems', 'linux_32.cmake')
191+
else:
192+
vcpkg_toolchain_file_path = os.path.join(sdk_source_dir, 'external',
193+
'vcpkg', 'scripts',
194+
'buildsystems', 'vcpkg.cmake')
195+
196+
cmd.append('-DCMAKE_TOOLCHAIN_FILE={0}'.format(vcpkg_toolchain_file_path))
197+
198+
vcpkg_triplet = get_vcpkg_triplet(arch, msvc_runtime_library)
199+
cmd.append('-DVCPKG_TARGET_TRIPLET={0}'.format(vcpkg_triplet))
200+
201+
if platform.system() == 'Windows':
202+
# If building for x86, we should supply -A Win32 to cmake configure.
203+
# Since the default architecture for cmake varies from machine to machine,
204+
# it is a good practice to specify it all the time (even for x64).
205+
cmd.append('-A')
206+
windows_cmake_arch_flag_value = 'Win32' if arch == 'x86' else 'x64'
207+
cmd.append(windows_cmake_arch_flag_value)
208+
209+
# Use our special cmake option to specify /MD (dynamic) vs /MT (static).
210+
if msvc_runtime_library == 'static':
211+
cmd.append('-DMSVC_RUNTIME_LIBRARY_STATIC=ON')
212+
213+
if target_format:
214+
cmd.append('-DFIREBASE_XCODE_TARGET_FORMAT={0}'.format(target_format))
215+
print('Running {0}'.format(' '.join(cmd)))
216+
subprocess.run(cmd, cwd=app_dir, check=True)
217+
218+
# CMake build.
219+
num_cpus = str(os.cpu_count())
220+
cmd = ['cmake', '--build', build_dir, '-j', num_cpus, '--config', config]
221+
print('Running {0}'.format(' '.join(cmd)))
222+
subprocess.run(cmd, cwd=app_dir, check=True)
223+
224+
225+
def build_app_with_prebuilt(app_dir, sdk_prebuilt_dir, build_dir, arch,
226+
msvc_runtime_library='static', config=None):
227+
"""Build desktop app directly against the prebuilt Firebase C++ libraries.
228+
229+
Since this involves a cmake configure, it is advised to run this on a clean
230+
build directory.
231+
232+
Args:
233+
app_dir (str): Path to directory containing application's CMakeLists.txt.
234+
sdk_prebuilt_dir (str): Path to prebuilt Firebase C++ libraries.
235+
build_dir (str): Output build directory.
236+
arch (str): Platform Architecture (eg: 'x64').
237+
msvc_runtime_library (str): Runtime library for MSVC.
238+
(eg: 'static', 'dynamic').
239+
config (str): Release/Debug config (eg: 'Release', 'Debug')
240+
If it's not specified, cmake's default is used (most likely Debug).
241+
"""
242+
243+
cmd = ['cmake', '-S', '.', '-B', build_dir]
244+
cmd.append('-DFIREBASE_CPP_SDK_DIR={0}'.format(sdk_prebuilt_dir))
245+
246+
if platform.system() == 'Windows':
247+
if arch == 'x64':
248+
cmd.append('-DCMAKE_CL_64=ON')
249+
if msvc_runtime_library == 'dynamic':
250+
cmd.append('-DMSVC_RUNTIME_MODE=MD')
251+
else:
252+
cmd.append('-DMSVC_RUNTIME_MODE=MT')
253+
254+
if config:
255+
cmd.append('-DCMAKE_BUILD_TYPE={0}'.format(config))
256+
257+
print('Running {0}'.format(' '.join(cmd)))
258+
subprocess.run(cmd, cwd=app_dir, check=True)
259+
260+
# CMake build.
261+
num_cpus = str(os.cpu_count())
262+
cmd = ['cmake', '--build', build_dir, '-j', num_cpus, '--config', config]
263+
print('Running {0}'.format(' '.join(cmd)))
264+
subprocess.run(cmd, cwd=app_dir, check=True)
265+
266+
267+
def main():
268+
args = parse_cmdline_args()
269+
270+
if not is_path_valid_for_cmake(args.sdk_dir):
271+
print('SDK path provided is not valid. '
272+
'Could not find a CMakeLists.txt at the root level.\n'
273+
'Please check the argument to "--sdk_dir".')
274+
sys.exit(1)
275+
276+
if not is_path_valid_for_cmake(args.app_dir):
277+
print('App path provided is not valid. '
278+
'Could not find a CMakeLists.txt at the root level.\n'
279+
'Please check the argument to "--app_dir"')
280+
sys.exit(1)
281+
282+
if is_sdk_path_source(args.sdk_dir):
283+
print('SDK path provided is a Firebase C++ source directory. Building...')
284+
build_source_vcpkg_dependencies(args.sdk_dir, args.arch,
285+
args.msvc_runtime_library)
286+
build_app_with_source(args.app_dir, args.sdk_dir, args.build_dir, args.arch,
287+
args.msvc_runtime_library, args.config,
288+
args.target_format)
289+
else:
290+
validate_prebuilt_args(args.arch, args.config)
291+
print('SDK path provided is Firebase C++ prebuilt libraries. Building...')
292+
build_app_with_prebuilt(args.app_dir, args.sdk_dir, args.build_dir,
293+
args.arch, args.msvc_runtime_library, args.config)
294+
295+
print('Build successful!\n'
296+
'Please find your executables in the build directory: {0}'.format(
297+
os.path.join(args.app_dir, args.build_dir)))
298+
299+
300+
def parse_cmdline_args():
301+
"""Parse command line arguments."""
302+
parser = argparse.ArgumentParser(description='Install Prerequisites for '
303+
'building cpp sdk.')
304+
parser.add_argument('--sdk_dir', help='Path to Firebase SDK - source or '
305+
'prebuilt libraries.',
306+
type=os.path.abspath)
307+
parser.add_argument('--app_dir', help="Path to application to build "
308+
"(directory containing application's CMakeLists.txt",
309+
type=os.path.abspath)
310+
parser.add_argument('-a', '--arch', default='x64',
311+
help='Platform architecture (x64, x86)')
312+
parser.add_argument('--msvc_runtime_library', default='static',
313+
help='Runtime library for MSVC '
314+
'(static(/MT) or dynamic(/MD)')
315+
parser.add_argument('--build_dir', default='build',
316+
help='Output build directory')
317+
parser.add_argument('--config', default='Release',
318+
help='Release/Debug config')
319+
parser.add_argument('--target_format', default=None,
320+
help='(Mac only) whether to output frameworks (default)'
321+
'or libraries.')
322+
args = parser.parse_args()
323+
return args
324+
325+
if __name__ == '__main__':
326+
main()

scripts/gha/build_desktop.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,8 @@ def cmake_configure(build_dir, arch, msvc_runtime_library='static',
180180
cmd.append('-A')
181181
cmd.append('Win32') if arch == 'x86' else cmd.append('x64')
182182

183-
# Use our special cmake option for /MD (dynamic).
184-
# If this option is not specified, the default value is /MT (static).
185-
if msvc_runtime_library == "dynamic":
183+
# Use our special cmake flag to specify /MD vs /MT
184+
if msvc_runtime_library == "static":
186185
cmd.append('-DMSVC_RUNTIME_LIBRARY_STATIC=ON')
187186

188187
if (target_format):

0 commit comments

Comments
 (0)