• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package nativelib creates the native library zip.
16package nativelib
17
18import (
19	"archive/zip"
20	"bufio"
21	"errors"
22	"flag"
23	"fmt"
24	"io/ioutil"
25	"log"
26	"os"
27	"path/filepath"
28	"sort"
29	"strings"
30	"sync"
31
32	"src/common/golang/fileutils"
33	"src/common/golang/flags"
34	"src/common/golang/ziputils"
35	"src/tools/ak/types"
36)
37
38var (
39	// Cmd defines the command to run nativelib.
40	Cmd = types.Command{
41		Init:  Init,
42		Run:   Run,
43		Desc:  desc,
44		Flags: []string{"lib", "native_libs_zip", "out"},
45	}
46
47	// Variables to hold flag values
48	nativeLibs    flags.StringList
49	nativeLibsZip flags.StringList
50	out           string
51
52	initOnce sync.Once
53)
54
55// Init initializes nativelib.
56func Init() {
57	initOnce.Do(func() {
58		flag.Var(&nativeLibs, "lib", "Path to native lib.")
59		flag.Var(&nativeLibsZip, "native_libs_zip", "Zip(s) containing native libs.")
60		flag.StringVar(&out, "out", "", "Native libraries files.")
61	})
62}
63
64func desc() string {
65	return "Nativelib creates the native lib zip."
66}
67
68// Run is the entry point for nativelib.
69func Run() {
70	if nativeLibsZip != nil {
71		dstDir, err := ioutil.TempDir("", "ziplibs")
72		if err != nil {
73			log.Fatalf("Error creating native lib zip: %v", err)
74		}
75
76		for _, native := range nativeLibsZip {
77			libs, err := extractLibs(native, dstDir)
78			if err != nil {
79				log.Fatalf("Error creating native lib zip: %v", err)
80			}
81			nativeLibs = append(nativeLibs, libs...)
82		}
83	}
84
85	if err := doWork(nativeLibs, out); err != nil {
86		log.Fatalf("Error creating native lib zip: %v", err)
87	}
88}
89
90func extractLibs(libZip, dstDir string) ([]string, error) {
91	zr, err := zip.OpenReader(libZip)
92	if err != nil {
93		return nil, err
94	}
95	defer zr.Close()
96
97	libs := []string{}
98	for _, f := range zr.File {
99		if f.Mode().IsDir() {
100			continue
101		}
102		arch := filepath.Base(filepath.Dir(f.Name))
103		libs = append(libs, fmt.Sprintf("%s:%s", arch, filepath.Join(dstDir, f.Name)))
104	}
105	if err := ziputils.Unzip(libZip, dstDir); err != nil {
106		return nil, err
107	}
108	return libs, nil
109}
110
111func doWork(nativeLibs []string, out string) error {
112	nativeDir, err := ioutil.TempDir("", "nativelib")
113	if err != nil {
114		return err
115	}
116	defer os.RemoveAll(nativeDir)
117	nativePaths, err := copyNativeLibs(nativeLibs, nativeDir)
118	if err != nil {
119		return err
120	}
121	zipFile, err := os.Create(out)
122	if err != nil {
123		return err
124	}
125	writer := bufio.NewWriter(zipFile)
126	zipWriter := zip.NewWriter(writer)
127	sort.Strings(nativePaths)
128	for _, f := range nativePaths {
129		p, err := filepath.Rel(nativeDir, f)
130		if err != nil {
131			return err
132		}
133		ziputils.WriteFile(zipWriter, f, p)
134	}
135	zipWriter.Close()
136	return nil
137}
138
139func copyNativeLibs(nativeLibs []string, dir string) ([]string, error) {
140	var paths []string
141	for _, cpuNativeLib := range nativeLibs {
142		r := strings.SplitN(cpuNativeLib, ":", 2)
143		if len(r) != 2 {
144			return nil, errors.New("error parsing native lib")
145		}
146		arch := r[0]
147		nativeLib := r[1]
148		if arch == "armv7a" {
149			arch = "armeabi-v7a"
150		}
151		libOutDir := filepath.Join(dir, "lib", arch)
152		if err := os.MkdirAll(libOutDir, 0777); err != nil && !os.IsExist(err) {
153			return nil, err
154		}
155		outNativeLibPath := filepath.Join(libOutDir, filepath.Base(nativeLib))
156		if err := fileutils.Copy(nativeLib, outNativeLibPath); err != nil {
157			return nil, err
158		}
159		paths = append(paths, outNativeLibPath)
160	}
161	return paths, nil
162}
163