In a static library project for iOS 6, some functions in a .c file is referenced by others, and therefore are considered global symbols, but should not be exposed to the user of this library.
How can I strip these function names out? Also, how can I hide those obj file names as well so that nobody could see the .o names in nm output?
I have tried to enable/set:
Deployment Postprocessing
Strip Debug Symbols During Copy
Strip Linked Product
Strip Stype: either 'Non-Global Symbols' or 'Debugging symbols'
Use Separate Strip
EDIT:
I see that there is another Build Setting item 'Additional Strip Flags'.
By adding in it a flag -R /path/to/symbol_list_file, strip command would remove symbols indicated in the file, or -s /path/to/exported_symbol_list_file -u to indicate interfaces and leaving undefined symbols at the same time.
No, you can't. A static library is simply a collection of object files and the object files within the static library have no special privileges over those using the static library.
You can obviously strip the final binary.
If you must hide symbols then they need to be static, which forces you to use fewer implementations files to allow the symbol to be shared, which is inconvenient.
Related
Is there a way to control the Bazel build to generate wanted temp files for a list of source files instead of just using the command line option "--save_temps"?
One way is using a cc_binary, and add "-E" option in the "copts", but the obj file name will always have a ".o". This kind of ".o" files will be overwriten by the other build targets. I don't know how to control the compiler output file name in Bazel.
Any better ideas?
cc_library has an output group with the static library, which you can then extract. Something like this:
filegroup(
name = "extract_archive",
srcs = [":some_cc_library"],
output_group = "archive",
)
Many tools will accept the static archive instead of an object file. If the tool you're using does, then that's easy. If not, things get a bit more complicated.
Extracting the object file from the static archive is a bit trickier. You could use a genrule with the $(AR) Make variable, but that won't work with some C++ toolchains that require additional flags to configure architectures etc.
The better (but more complicated) answer is to follow the guidance in integrating with C++ rules. You can get the ar from the toolchain and the flags to use it in a custom rule, and then create an action to extract it. You could also access the OutputGroupInfo from the cc_library in the rule directly instead of using filegroup if you've already got a custom rule.
Thanks all for your suggestions.
Now I think I can solve this problem in two steps(Seems Bazel does not allow to combine two rules into one):
Step1, add a -E option like a normal cc_libary, we can call it a pp_library. It is easy.
Step2, in a new rules, its input is the target of pp_library, then in this rule find out the obj files(can be found via : action.outputs.to_list()) and copy them to the a new place via ctx.actions.run_shell() run_shell.
I take Bazel: copy multiple files to binary directory as a reference.
I have a qmake project in which I cannot debug because something adds -O2 -g to the end of the compiler flags in debug mode, overriding all my debug and optimization flags. I have greped the whole project for -O2 and there is none (I removed the one I had for release). Deleting the build folder and running qmake again didn't help. I'm trying to track down what adds compiler flags, but I'm missing something.
Known things that can add compiler flags:
QMAKE_CXXFLAGS - Adds flags as given in all builds.
QMAKE_CXXFLAGS_DEBUG - Adds flags as given in debug builds.
QMAKE_CXXFLAGS_RELEASE - Adds flags as given in release builds.
CONFIG - Adds flags that are difficult to trace. CONFIG += strict_c++ and CONFIG += c++17 managed to not have my -std=c++17 overwritten, but I can't tell what other flags that adds. Also the qmake call contains CONFIG+=debug which may or may not add other flags. I can't tell from the documentation.
mkspec - In projects->build it lists the effective qmake call which includes for example -spec linux-g++ which I think includes /usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++/qmake.conf which includes more files which add platform-dependent flags. Removing the spec flag didn't remove the undesired -O2 flag though. Also it works for other projects, so it's probably not the culprit.
TEMPLATE - Specifies how the project is organized. Normally it's just APP, but this one uses subdirs which may override flags as all sub projects need to have the same flags.
An ideal answer would list all ways to add compiler flags, in which order they are added, an explanation how to check what flags they add and how to change them.
What qmake does it simply produces a makefile. A generated Makefile only uses compiler flags from CXXFLAGS (plus DEFINES) and INCPATH make variables, unless you have some handcrafted rules. It is clearly viewable from a generated makefile.
And these make variables come directly from qmake vars, such as QMAKE_CXXFLAGS, DEFINES and INCLUDEPATH. (This is done internally in qmake source code; well, actually the stuff could be more complicated on some platforms, so refer to qmake source code too).
Now, QMAKE_CXXFLAGS is just a qmake's variable. So, in principle, it can be modified at any line of any qmake script. Given that these scripts depend on OS/arch/compiler/Qt build options/App options etc. your expectations of "an ideal answer" are overstretched too far.
But, roughly speaking, qmake sources its scripts in the following order (hint: see full dependency list in a generated makefile):
features/spec_pre.prf
<QMAKE-SPEC>/qmake.conf (usually includes features/qt_config.prf and a ton of Qt-related stuff)
features/spec_post.prf
features/default_pre.prf
<user project>
features/default_post.prf
all features/xxx.prf according to the final CONFIG value (note: order reversed!)
So if you miss some flag in your project, it probably originates either from default_post.prf (like release flags for release build), or from CONFIG (i.e. features/xxx.prf).
I've got an iOS framework that has a dependency on the (presumably Google maintained) pod called '!ProtoCompiler'. In order to build my framework I'm going to need it in the sandbox. So, I have a genrule and can try to include it with
src = glob(['Pods/!ProtoCompiler/**/*']) but I get the following error:
ERROR: BUILD:2:1: //Foo:framework-debug: invalid label 'Pods/!ProtoCompiler/google/protobuf/any.proto' in element 1118 of attribute 'srcs' in 'genrule' rule: invalid target name 'Pods/!ProtoCompiler/google/protobuf/any.proto': target names may not contain '!'.
As is, this seems like a total blocker for me using bazel to do this build. I don't have the ability to rename the pod directory as far as I can tell. As far as I can tell, the ! prohibition is supposed to be for target labels, is there any way I can specify that this is just a file, not a label? Or are those two concepts completely melded in bazel?
(Also, if I get this to work I'm worried about the fact that this produces a .framework directory and it seems like rules are expected to produces files only. Maybe I'll zip it up and then unzip it as part of the build of the test harness.)
As far as I can tell, the ! prohibition is supposed to be for target
labels, is there any way I can specify that this is just a file, not a
label? Or are those two concepts completely melded in bazel?
They are mostly molded.
Bazel associates a label with all source files in a package that appear in BUILD files, so that you can write srcs=["foo.cc", "//bar:baz.cc"] in a build rule and it'll work regardless of foo.cc and baz.cc being a source file, a generated file, or a build rule's name that produces files suitable for this particular srcs attribute.
That said you can of course have any file in the package, but if the name won't allow Bazel to derive a label from it, then you can't reference them in the BUILD file. Since glob is evaluated during loading and is expanded to a list of labels, using glob won't work around this limitation.
(...) it seems like rules are expected to produces files only. Maybe
I'll zip it up and then unzip it as part of the build of the test
harness.
Yes, that's the usual approach.
Inspecting an archived app, I can see the full path listed for a few source code files in the app binary. Not all source code files are listed.
strings - the_binary_app | grep "\.m"
reveals
/Users/bbarnhart/myPath/myPath/App/path/path/SourceCodeFile.m
as well as a few others. I can not determine how the full paths for a few source code files are embedded in the app binary. I would like to remove them. Any ideas? Is this a build setting or is the project file slightly corrupted?
Some belong to a lib and others are files that belong to the project.
The __FILE__ macro expands to full path to the current file. This is one likely way you might be getting the paths into your executable. For example, the expansion of the assert macro includes the __FILE__ macro.
Look at the output of your strings | grep pipeline. For each of those files, go into your project in Xcode and open that file. Then go to the Related Files doodad and choose “Preprocess”:
Then search through the preprocessor output for the file's path. You will find lots of false positives, because there will be lots of # line number/path directives. You can ignore these, because they only produce debug output, which is not included in your executable file (unless you've done something weird with your build settings). You might find it faster to save the preprocessor output to a file, then open that file and pipe it through grep or use a regexp search/replace to delete all lines starting with #.
Find the other instances where your path appears as a string constant. For example, if you used the assert macro, you will find something like this:
(__builtin_expect(!(argc > 0), 0) ? __assert_rtn(__func__, "/Volumes/b/Users/mayoff/TestProjects/textViewChanged/textViewChanged/main.m", 16, "argc > 0") : (void)0);
That's a case where the path will end up embedded in your executable.
If that doesn't find all the places where you're embedding your path, try selecting “Assembly” from the Related Files doodad. The assembly will be full of comments containing your path; everything after # is a comment in the assembly output, so ignore those.
You will also see your paths in .file directives. I believe these only produce debug symbol output, which doesn't go into your executable, so you can ignore those too.
You will also see your paths in .asciz directives shortly after .section DWARF,... directives. This is more debug symbol stuff that you can ignore.
Look for the remaining cases where your path appears in the assembly output. You need to figure out how to eliminate these cases. How you do that will depend on the context in which the paths appear, so if you need more help, update your question with what you find.
Sounds like your code contains the __FILE__ macro somewhere.
I have a static library, where one of the objects defines a symbol:
nm mylib.a
...
00007340 t _a_local_symbol
...
I need to access the function from my C code. Obviously, I don't have the source code for the library, so I can work only with the archive file that I have at hand.
This is further restricted by iOS linker.
A bit more context. The library is Objective-C++, the function in question is pure C. I don't have original headers, but I've got the function signature restored.
objcopy has a flag to do what you want:
--globalize-symbol <name> Force symbol <name> to be marked as a global
Not sure whether objcopy works on iOS object files though.