Xcode oclint analyzer - xcode

I want to use oclint (an Objective-C static analyzer) for my projects but the official documentation does not clearly describe how to configure it.
How do I use it?
I have installed the oclint package then copied the script for capturing projects configs into a project's folder. Running this script creates an empty file named compile_commands.json and it does not fill xcodebuild.log with any data.
Thank you!

I don't think this script will add anything into xcodebuild.log. It reads from it. You may want to manually run xcodebuild and save the output into xcodebuild.log before running the script.
Check out the documentation.

I have had luck with the manual route of copying the script into my project's folder then executing it on the command line.
Though this does not integrate oclint's functionality into XCode, it does provide feedback via stdout.
From this feedback I then update my code to align with oclint's recommendation and iteratively run oclint until my code complies with oclint's rules.

Related

'swift package dump-package' command does not work on build pre-action and build phase

I want to list in a view of my app all open source dependencies I use.
As dependencies manager, I am using Swift Package Manager.
By doing some searches, I discovered that there is a SPM command to list dependencies in JSON format, which is perfect for my feature.
swift package dump-package
Moreover, I do not want execute this command manually each time a new dependency is added in my Package.swift file. So, my idea was to add a script in the "Target Build Phases" to write the result of the command in a JSON file. Then I could use the JSON file directly in my app to display dependencies informations.
The problem is that the command work well when I execute it from the Terminal but not from a script executed from "Target Build Phases". I also tried to execute the command from "Build Pre-Action" but it do not work too.
Here the full command I use to generate the JSON with the errors I get:
swift package --package-path ${PROJECT_DIR}/SwiftPackageManager/AppDependencies dump-package > ${PROJECT_DIR}/dependencies.json
Can someone explain me why I get this errors ?
What's the right solution to do my feature ?
My configuration:
Xcode 12.4
swift-tools-version:5.2
Thanks in advance for your answers and reactions

How can I make “gradle --console=rich” the default?

Along the lines of this answer (which works for me, BTW) and the javadocs, I tried
gradle.startParameter.consoleOutput = org.gradle.api.logging.configuration.ConsoleOutput.Rich
in my ~/.gradle/init.gradle. However, I still need --console=rich to get color output. Why?
Tested with Gradle 2.14.1 and 3.2.1.
Terminal is cygwin urxvt with TERM variable set to rxvt-unicode-256color.
Since Gradle 4.3 you can use org.gradle.console property in gradle.properties:
org.gradle.console=rich
A new console verbose mode will print outcomes of all tasks (like UP-TO-DATE) like Gradle 3.5 and earlier did. You can set this via --console=verbose or by a new Gradle property org.gradle.console=(plain rich verbose).
I am not sure if you can force the rich console from a gradle script, as the detection happens likely before the script is interpreted.
NativeServices class provides the integration with the console. If you look at the source code, there are two messages possibly printed in log:
Native-platform terminal integration is not available. Continuing with fallback.
Unable to load from native-platform backed ConsoleDetector. Continuing with fallback.
The latter might give you more information why. Try running the gradle script with --debug. You will likely find out that you are missing a native library that is either not available in cygwin or it is, but is not on library path.
I believe it works when you specify the rich console from the command line, because gradle forces the colours even though the console doesn't indicate it supports them.
Does it work if you don't use the cygwin console in Windows native command line or maybe GitBash?
There is a workaround how you can make this work. You can create an alias in cygwin that will always add the --console=rich.
If you are using gradle wrapper, you can edit the gradlew script and add the command line parameter. To make it automated, you can change the wrapper task to alter your script in the doLast part.
Create a file called gradle.properties inside your ~/.gradle/ folder.
Inside gradle.properties, add the line org.gradle.console=rich.
Each builds will run under --console=rich automatically because the new gradle.properties will be merged with the gradle.properties of your project.
If your project's gradle.properties contains the same tag as the local file, your project's will be used overriding the local file's
If you are on Linux/Mac set
alias gradle='gradle --console rich'
in your ~/.bashrc.
In Gradle Wrapper, add the following line:
org.gradle.console=rich
to ./gradle.properties in the root folder, where the gradlew script is located.

how to use appledoc to generate an Apple-like documentations

I am reading on the article how to generate an Apple-like HTML documentation at here. My questions are what the command lines are used for. How can we combine command lines and appledoc xcode project to generate a HTML.
I'm the author of appledoc tool. The tool is intended to be used as answered by Caleb above. Recommended installation method is to clone repository from GitHub, open project in Xcode, build and optionally copy binary to your path as suggested above. Additionally, you must also copy template files required for running the tool to one of predefined paths. All the steps required are described in the readme file on appledoc page on GitHub, see Quick Install section.
There are also other methods for installing - all contribution from users:
You can use install-appledoc.sh script included in the git repository.
There's also homebrew recipe available, although it doesn't install template files to my understanding (see this link).
For any additional questions go to appledoc Google group. I just created it few days ago, so there's no content at the moment of this writing, but feel free to ask questions there.
I haven't used 'appledoc', but from a quick look at the page you linked it appears that it's an open-source command-line utility. So the first step will be to compile the 'appledoc' program itself, and then stick it in a directory that's in your path, such as /usr/local/bin or ~/bin/.
The next step is to try to use it to generate some documentation (assuming that you've already created the markdown files that it consumes). Open a terminal window, navigate to the directory where your files are, and then use the command given at the top of the page that you linked:
appledoc --project-name appledoc --project-company "Gentle Bytes" --company-id com.gentlebytes --output ~/help .
If you want to use 'appledoc' to regenerate your documentation every time you build some project, you can add a "Run Script" build phase to an existing target in your project, or create a new target just for documentation that has nothing but a "Run Script" build phase. Either way, the script in that phase should be shell script containing a command similar to the one above (though you'll probably want to specify the source directory explicitly rather than just using the 'current' directory, i.e. .).
As I found on this post, you can generate a complete HTML documentation of your code with this command line:
appledoc --project-name BabelCPP --project-company "My Name"
--company-id com.mycompany --no-create-docset --output ./doc/ .
The last "." is the path to your code.

How do I use Mogenerator?

I installed Mogenerator. Now what do I do? How do I use it?
The first problem I have is that I have no idea where it was installed to. During the install process, it only let me select the hard drive to install it on, not the directory. The most natural location would be the Applications folder, but it isn't there.
Next, the readme (which I found online) states:
Xmo'd works by noticing when your
*.xcdatamodel is saved. If the model file's Xcode project item comment
contains xmod, an AppleScript is fired
that creates a folder based on your
model's file name and populates it
with derived source code files from
your model. It then adds the new
folder to your project as a Group
Reference and adds all the source
files to your project.
There are several issues with the above statement that aren't clear:
What does "the model file's Xcode project item comment" refer to? How can I make it contain "xmod"?
Is adding this comment and having mogenerator monitor the .xcdatamodel file the only way to use mogenerator? Is there any way I can manually run mogenerator so that it recreates the generated files?
One more caveat to be aware of: You have to already set the Class properties of your entities to something different than NSManagedObject. Otherwise Xmo'd won't do anything.
Note: Xmo'd currently doesn't work with Xcode 4/5, afaik.
What I do is just add a "MOGenerator" target in Xcode:
Go to your project and click on "Add Target..." in the "Targets" section.
Choose "iOS -> Other -> Aggregate"
Go to "Build Phases"
Select from the Menu "Editor -> Add Build Phase -> Add Run Script Build Phase"
Paste your MOGenerator command into the Run Script section, for example:
PATH=${PATH}:/usr/local/bin
cd "${PROJECT_DIR}/MyApp"
mogenerator --human-dir Classes --machine-dir MOGenerated --model MyApp.xcdatamodeld/MyApp.xcdatamodel --template-var arc=true
Now you can update your MOGenerator-generated by simply running this target.
mogenerator is a script that is installed into your developer directory as I recall. However it might be installed into the Xcode scripts directory under your ~/Library.
What do you mean by manually triggering the application? You can trigger a build by "touching" the data model. Any save on the data model will trigger the build
In Xcode if you select the model file and hit ⌘I you will get its metadata. Click on the comments tab and add xmod there. mogenerator looks for that comment to know if it should generate files.
Update
You can run mogenerator from the command line as well as have it monitor your files. Type mogenerator --help in the Terminal to see the options.
I searched my hard drive and found the following files:
The application is installed to: /usr/bin/mogenerator.
The /Library/Application Support/mogenerator/ directory contains some .motemplate files.
⌘I doesn't work in Xcode 4 any more. please check out the command line tool. Here is the doc
Studying line 22 of make_installer.command, I found that /Developer/Library/Xcode/Plug-ins/Xmod.pbplugin is also installed.
And then, searching mogenerator GitHub Issues for "uninstall," I found official instructions on how to uninstall mogenerator from the creator himself.
using mogenerator:
download mogenerator
run and build the mogenerator project
locate the built file in the product group
copy the built file in to /usr/bin directory
in the terminal copy this code and hit enter:
mogenerator -m /Users/hashem/Desktop/Projects/myApp/myAppModel.xcdatamodel -O /Users/hashem/Desktop/Projects/myApp/managedObjects --template-var arc=true
NOTE: here first I have entered myApp.xcdatamodel file path, and next path is the location of generated files. if the file path contains space character be sure to add \ character before space in the file path. like /desktop/xcode\ projects/myApp/....
enjoy!

Xcode: Running a script before every build that modifies source code directly

What I did:
I have a script that
Read some configuration files to generate source code snippets
Find relevant Objective-C source files and
Replace some portions of the source code with the generated code in step 1.
and a Makefile that has a special timestamp file as a make target and the configuration files as target sources:
SRC = $(shell find ../config -iname "*.txt")
STAMP = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME).stamp
$(STAMP): $(SRC)
python inject.py
touch $(STAMP)
I added this Makefile as a "Run Script Build Phase" on top of the stack of build phases for the project target.
What happened:
The script build phase was run before compiling the source.
However, since the script modifies source code during its execution, I needed to build twice to get the most recent version of the build product. Here is what I imagine to be happening:
1st run: Xcode collects dependency information ---> no changes
1st run: Xcode runs "Run Script Build Phase" ---> source is changed behind Xcode's back
1st run: Xcode finishes build, thinking nothing needs to be updated
2nd run: Xcode collects dependency information ---> source has changed, needs rebuild!
2nd run: Xcode runs Run Script Build Phase" ---> everything is up-to-date
2nd run: Xcode proceeds to compilation
After reading Xcode documentation on Build Phases, I tried adding a source file which is known to be updated every time the script is run as the output of "Run Script Build Phases", but nothing changed. Since the number of configuration files may vary in my project, I don't want to specify every input and output file.
Question:
How do I make Xcode aware of source file changes made during "Run Script Build Phase"?
Edit:
Added that I placed the script build phase before the other build phases
Every technique mentioned so far is an overkill. Reproducing steve kim's comment for visibility:
In the build phases tab, simply drag the "Run Script" step to a higher location (e.g. before "Compile Sources").
Tested on Xcode 6
This solution is probably outdated. See the higher voted answer instead; I no longer actively use Xcode and am not qualified to vet a solution.
Use "External Target":
Select "Project" > "New Target..." from the menu
Select "Mac OS X" > "Other" > "External Target" and add it to your project
Open its settings and fill in your script setup
Open the "General" tab of the main target's settings and add the new target as it's direct dependency
Now the new "External Target" runs before the main target even starts gathering dependency information, so that any changes made during the script execution should be included in the build.
There is another, slightly simpler option that doesn't require a separate target, but it's only viable if your script tends to modify the same source files every time.
First, here's a brief explanation for anyone who's confused about why Xcode sometimes requires you to build twice (or do a clean build) to see certain changes reflected in your target app. Xcode compiles a source file if the object file it produces is missing, or if the object file's last-modified date is earlier than the source file's last-modified date was at the beginning of the first build phase. If your project runs a script that modifies a source file in a pre-compilation build phase, Xcode won't notice that the source file's last-modified date has changed, so it won't bother to recompile it. It's only when you build the project a second time that Xcode will notice the date change and recompile the file.
Here's a simple solution if your script happens to modify the same source files every time. Just add a Run Script build phase at the end of your build process like this:
touch Classes/FirstModifiedFile.m Classes/SecondModifiedFile.m
exit $?
Running touch on these source files at the end of your build process guarantees that they will always have a later last-modified date than their object files, so Xcode will recompile them every time.
As of Xcode 4, it looks like if you add the generated files to the output section of the build phase, it will respect that setting, and not generate the ... has been modified since the precompiled header was built error messages.
This is a good option if your script is only generating a handful of files each time.
I as well struggled with this for a long time. The answer is to use ento's "External Target" solution. He is WHY this problem occurs and how we use it in practice...
Xcode 4 build steps do not execute until AFTER the plist has been compiled. This is silly, of course, because it means that any pre-build steps that modify the plist won't take effect. But if you think about it, they actually DO take effect...on the NEXT build. That's why some people have talked about "caching" of plist values or "I have to do 2 builds to make it work." What happens is the plist is built, then your script runs. Next time you build, the plist builds using your modified files, hence the second build.
ento's solution is the one way I've found to actually do a true pre-build step. Unfortunately I also found that it does not cause the plist to update without a clean build and I fixed that. Here is how we have data-driven user values in the plist:
Add an External Build System project that points to a python script and passes some arguments
Add user-defined build settings to the build. These are the arguments that you pass to python (more on why we do this later)
The python script reads some input JSON files and builds a plist preprocessor header file AND touches the main app plist
The main project has "preprocess plist files" turned on and points to this preprocessor file
Using touch on the main app plist file causes the main target to generate the plist every time. The reason we pass in build settings as parameters is so our command-line build can override settings:
Add a user-defined variable "foo" to the prebuild project.
In your prebuild you can use $(foo) to pass the value into the python script.
On the command-line you can add foo=test to pass in a new value.
The python script uses base settings files and allows for user-defined settings files to override the defaults. You make a change and immediately it ends up in the plist. We only use this for settings that MUST be in the plist. For anything else it's a waste of effort....generate a json file or something similar instead and load it at run-time :)
I hope this helps...it's been a couple rough days figuring this out.
The External Target solution from #ento no longer works as of Xcode 11.5. The solution is to add all files that will be changed under Output Files in the Run Script.
Another option is to create a subproject framework with your scripts and just add it as a dependency to all targets. The phase scripts of this subproject should now be executed before all targets.

Resources