'cocoapods' how to edit podspec file - ios

Example taken from https://guides.cocoapods.org/syntax/podspec.html#requires_arc:
spec.requires_arc = ['Classes/*ARC.m', 'Classes/ARC.mm']
What is the meaning of the following? Can you give an example that to use? Thanks!
Classes/*ARC.m
Classes/ARC.mm

According to the Cocoapods documentation (which you're presumably looking at right now), your choices are "true", "false" or the actual files that require ARC (automated-ref-counting).
So for the Podspec pattern spec.requires_arc = ['Classes/*ARC.m', 'Classes/ARC.mm'] you'd be saying that any files in the "Classes" directory that are either named ARC.mm or *ARC.m (i.e. * being a wildcard so "ChenFanFangARC.m would be a valid match while ARCMichael.m is not), these files are expected to work with Automated Reference Counting.
All other files compiled for this pod would have ARC turned off.

Related

What are the options to fix/work-around a bazel package conflict?

I'm seeing the following error:
link: package conflict error: google.golang.org/genproto/googleapis/api/annotations: multiple copies of package passed to linker:
#go_googleapis//google/api:annotations_go_proto
#org_golang_google_genproto//googleapis/api/annotations:annotations
Set "importmap" to different paths or use 'bazel cquery' to ensure only one
package with this path is linked.
#org_golang_google_genproto//googleapis/api/annotations:annotations is being brought in through:
#com_github_uber_cadence//service/history:go_default_library
#com_github_uber_cadence//service/history:history
#com_github_uber_cadence//common/resource:resource
#com_github_uber_cadence//common/archiver/provider:provider
#com_github_uber_cadence//common/archiver/gcloud:gcloud
#com_github_uber_cadence//common/archiver/gcloud/connector:connector
#com_google_cloud_go_storage//:storage
#org_golang_google_genproto//googleapis/iam/v1:iam
#org_golang_google_genproto//googleapis/api/annotations:annotations
Can #org_golang_google_genproto//googleapis/api/annotations:annotations be disabled or shadowed by #go_googleapis//google/api:annotations_go_proto? If so, how?
Option I went with:
Change what uses #org_golang_google_genproto//googleapis/api/annotations to use #go_googleapis//google/api:annotations_go_proto instead by using appropriate gazelle:resolve directives in the repositories.bzl file:
go_repository(
name = "com_google_cloud_go",
build_directives = [
# #go_googleapis is the modern version of #org_golang_google_genproto
# use #go_googleapis to avoid dependency conflicts between the two
"gazelle:resolve go google.golang.org/genproto/googleapis/iam/v1 #go_googleapis//google/iam/v1:iam_go_proto", # keep
],
…
)
go_repository(
name = "com_google_cloud_go_storage",
build_directives = [
# #go_googleapis is the modern version of #org_golang_google_genproto
# use #go_googleapis to avoid dependency conflicts between the two
"gazelle:resolve go google.golang.org/genproto/googleapis/iam/v1 #go_googleapis//google/iam/v1:iam_go_proto", # keep
"gazelle:resolve go google.golang.org/genproto/googleapis/type/expr #go_googleapis//google/type:expr_go_proto", # keep
"gazelle:resolve go google.golang.org/genproto/googleapis/api/annotations #go_googleapis//google/api:annotations_go_proto", # keep
],
…
)
The following also works but I preferred the above since it uses the newer library:
Change what uses #go_googleapis//google/api:annotations_go_proto to use #org_golang_google_genproto//googleapis/api/annotations instead by using appropriate gazelle:resolve directives in the root BUILD file:
# gazelle:resolve go google.golang.org/genproto/googleapis/api/annotations #org_golang_google_genproto//googleapis/api/annotations
Other options considered and reasons I didn't go with them:
Upgrade to the latest #com_google_cloud_go_storage. Didn't go with this option because the latest version (v1.24.0 at the time of this post) still uses #org_golang_google_genproto.
Upgrade #com_google_cloud_go_storage to use #go_googleapis. Didn't go with this option because it looked too difficult to get merged.
repo_mapping = {"#org_golang_google_genproto" : "#go_googleapis"} for com_google_cloud_go_storage. Didn't go with this option because #go_googleapis isn't a drop-in replacement for #org_golang_google_genproto (#go_googleapis uses the prefix google while #org_golang_google_genproto uses the prefix googleapis).
"gazelle:exclude **/common/archiver/gcloud/**" for com_github_uber_cadence. Didn't go with this option because common/archiver/provider depends on common/archiver/gcloud.
Set prefix for go_googleapis from google to googleapis. Didn't go with this option because it breaks expectations for those familiar with go_googleapis standard practice.

How to write Bazel rules that work with external repositories?

The Bazel Starlark API does strange things with files in external repositories. I have the following Starlark snippet:
print(ctx.genfiles_dir)
print(ctx.genfiles_dir.path)
print(output_filename)
ret = ctx.new_file(ctx.genfiles_dir, output_filename)
print(ret.path)
It is creating the following output:
DEBUG: build_defs.bzl:292:5: <derived root>
DEBUG: build_defs.bzl:293:5: bazel-out/k8-fastbuild/genfiles
DEBUG: build_defs.bzl:294:5: google/protobuf/descriptor.upb.c
DEBUG: build_defs.bzl:296:5: bazel-out/k8-fastbuild/genfiles/external/com_google_protobuf/google/protobuf/descriptor.upb.c
That extra external/com_google_protobuf comes seemingly out of nowhere, and it makes my rule fail:
I tell protoc to generate into ctx.genfiles_dir.path (which is bazel-out/k8-fastbuild/genfiles).
So protoc generates bazel-out/k8-fastbuild/genfiles/google/protobuf/descriptor.upb.c
Bazel fails because I didn't generate bazel-out/k8-fastbuild/genfiles/external/com_google_protobuf/google/protobuf/descriptor.upb.c
Likewise, when I try to call file.short_path on a source file from an external repository, I get a result like ../com_google_protobuf/google/protobuf/descriptor.proto. This seems quite unhelpful, so I just wrote some manual code to strip off the leading ../com_google_protobuf/.
Am I missing something? How can I write this rule in a way that doesn't feel like I'm fighting Bazel the whole time?
Am I missing something?
The basic problem, as you already realized, is that you have two path "namespaces" the one that protoc sees (i.e. import paths) and the one that bazel sees (i.e. the path you pass to declare_file().
2 things to note:
1) All paths declared with declare_file() get the path <bin dir>/<package path incl. workspace>/<path you passed to declare_file()>
2) All actions are executed from <bin dir> (unless output_to_genfils=True in which case this switches to <gen dir> as in your example.
Trying to solve the exact same problem you encountered, I resorted to stripping the known path from the output_file's path to determine which directory to pass as p:
# This code is run from the context of the external protobuf dependency
proto_path = "google/a/b.proto"
output_file = ctx.actions.declare_file(proto_path)
# output_file.path would be `<gen_dir>/external/protobuf/google/a/b.proto`
# Strip the known proto_path from output_file.path
protoc_prefix = output_file.path[:-len(proto_path)]
print(protoc_prefix) # Prints: <gen_dir>/external/protobuf
command = "{protoc} {proto_paths} {cpp_out} {plugin} {plugin_options} {proto_file}".format(
...
cpp_out = "--cpp_out=" + protoc_prefix,
...
)
Alternatives
You may also be able to construct the same path with ctx.bin_dir, ctx.label.workspace_name, ctx.label.package, and ctx.label.name.
Misc.
proto_library recently gained an attribute strip_import_prefix. When used, the above is not correct, as all dependent files are symlinked into a new directory from which they have the relative paths declared with strip_import_prefix.
The path format is:
<bin dir>/<repo>/<package>/_virtual_base/<label name>/<path `import`ed in .proto files>
i.e.
<bin dir>/external/protobuf/_virtual_base/b_proto/google/a/b.proto
Assuming you are building an external repo called protobuf, which contains a BUILD file at its root with a target named b_proto, which in turn, relies on a proto_library wrapping google/a/b.proto AND uses the strip_import_prefix attribute.

Does Bazel need external-repo BUILD files to be in $WORKSPACE_ROOT/external?

I made a repository for glfw with this:
load("#bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository")
new_git_repository(
name = "glfw",
build_file = "BUILD.glfw",
remote = "https://github.com/glfw/glfw.git",
tag = "3.2.1",
)
I put BUILD.glfw in the WORKSPACE root. When I built, I saw:
no such package '#glfw//': Not a regular file: [snipped/external/BUILD.glfw
I moved BUILD.glfw to external/BUILD.glfw and it seems to work, but I couldn't find documentation about this. The docs about new_git_repository say that build_file "...is a label relative to the main workspace."; I don't see anything about 'external' there.
This is due to an inconsistent semantical difference between the native and (newer) Skylark versions of new_git_repository. To use the native new_git_repository, comment/remove the load statement:
# load("#bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository")
Assuming that new_git_repository has the same problem that http_archive has, per Bazel issue 6225 you need to refer to the BUILD file for glfw as #//:BUILD.glfw

What podspec parameter to use for source file path?

I have a file hierarchy similar to this one:
File hierarchy image
And I need to capture in the visible area all the folders and files (swift and ObjC) that lie in the TestFramework. What podspec parameter to use for source file path? I try to use this:
s.source_files = "TestFramework/**/*"
Is the correct parameter I use?
Okey, s.source_files = "TestFramework/**/*" is correct parameter for my situation.
/** - matches directories recursively.
/* - matches any file.
Sometimes it is necessary to limit the type of files that should be visible. For such situations, the following parameters are used:
s.source_files = "TestFramework/**/*.{h,m,swift}"

Xcode Localizable.string multiple targets issue

I have a project with multiple targets, which represent the same app just with different styling and translations.
Since almost whole project looks the same for each target, I need to have just few strings in Localizable.strings file, that I need to be different. And I don't want to copy whole huge Localizable.strings file to each project just because of the fact it has few lines different.
It is required for me to have just 1 strings file because of third-party libraries/SDK that are included in project. So I cannot use tableName for localizedString.
The problem is - I need to have a flexible possibility to override just few lines from Localizable.strings for each target separately. And I don't like the idea just to copy whole file to each target, cause it will lead to annoying flow in the future, in case I will have 10 targets and I need to add 1 string to all of them.
The goal is to have 1 huge Localizable.strings file with all strings included, that would be common for all targets, and have small configuration for each target for the strings that should tell different. So target's file should kinda merge and override the one that is common.
AFAIK it is not natively supported by Xcode, so I'm probably looking for a script that would make it works.
So, script should look into common and target's Localizable files, merge them, and in case some keys are defined in both, then it should use the one from target's file.
Can anyone help me with such script?
P.S. Similar issue exists with .xcassets, and CocoaPods solves it by merging multiple assets into 1, and it works as expected - if some targets has an asset containing the image with the same name that is already included into a common asset, then the one from target will replace it.
P.S.2. Similar feature is natively supported for Android devs - each image, each translations can be overridden by "child" flawor, or whatever it is called :)
TL;DR:
Example project: https://github.com/JakubMazur/SO45279964
OK, the easier thing to do would be shell/python script, because it will work for every build server. I assume that you have a different scheme for each target (otherwise it will make no sense). So what you can do is:
Let's say your target is named:
target1
target2
target3
1) Create separate files contains all the strings that should be different (i will put it under Localizable directory.
Your Localizable.strings file may look like this:
"someGeneralString" = "General string 1";
"AppName" = "This is a string that you probably need to change";
"someOtherGeneralString" = "General string 2";
And any of your targetX.strings file may look like this:
"AppName" = "target[x]"
And here is how it should look like in your project:
Note that your target localizable files should has target membership set only to one target, but your Localizable.strings should be for all targets!
That's all for project configuration. Let's go to scripting (I will use python for that):
#!/usr/bin/python
import sys
supportedLanguages = ["en","pl"]
commonPath = ".lproj/Localizable.strings"
keys = ["AppName"]
class CopyLocalizable():
target = ""
def __init__(self,arg):
self.target = arg
self.perform()
def perform(self):
for lang in supportedLanguages:
pathToLocalizable = lang+commonPath
textToFile = ""
with open(pathToLocalizable,"r") as languageFile:
for line in languageFile.readlines():
for key in keys:
if key in line:
textToFile += self.foundAndReplace(key,lang)
else:
textToFile += line
self.saveInFile(pathToLocalizable,textToFile)
def foundAndReplace(self,key,lang):
pathToTargetFile = "Localizable/"+lang+".lproj/"+self.target+".strings"
with open(pathToTargetFile,"r") as targetFile:
for targetLine in targetFile.readlines():
if key in targetLine:
return targetLine
def saveInFile(self,file,stringToSave):
with open(file,"w+") as languageFile:
languageFile.write(stringToSave)
You can optimize it yourself. It's easier script i can think about to get a job done.
And in the end let's automate it a bit:
- Go to your target
- add a new build phase
- Add a new script:
export PATH="/usr/local/bin:$PATH"
cd SO45279964/
python localize.py target[x]
and watch a magic happen ;)
http://www.giphy.com/gifs/26n6NKgiwYvuQk7WU
Here you can find example project that I've created to run this example:
https://github.com/JakubMazur/SO45279964
To keep it simple, Have a Macro defined for each target in Build Settings & define target specific strings within macro section like
#ifdef __TARGET__
//key values in localizable file
#endif

Resources