Building test targets in Chromium

Generally, we use 'gn gen out/Debug' and 'ninja -C out/Debug chrome' to build the chromium. Sometimes we need some unit tests to be built and run to test those changes. Mostly the unit test targets had already generated by gn gen command. So all we have to do is look for the target name and invoke it from command line.

  1. Look for the ninja build file that containing the unit test source you want to build. For example, the ninja build file containing  'base/files/file_path_unittest.cc' is 'obj/base/base_unittests.ninja', which is driven by 'build.ninja' by a line 'build base$:base_unittests: phony ./base_unittests'.
  2. So, run 'ninja -C out/Debug base:base_unittests' to build the base_unittests executable file.
  3. That’s all.

Build Qt from source and install it on Windows

The major problem is its installation.

1. Suing shadow building. Configure the building in a side directory.

configure --target xp --prefix the-correct-path-to-install -D _USING_V110_SDK71_ 

For example,

configure --target xp --prefix C:/Qt/5.6.3/msvc2015_xp -D _USING_V110_SDK71_ 

The correct install path is important, since a qconfig.cpp file would be generated with this path inside.

2. nmake
3. nmake install INSTALL_ROOT=any-directory-you-want

The directory specified in INSTALL_ROOT variable is a temporary location.

4. Copy all things under INSTALL_ROOT/Qt/5.6.3/qtbase/ to your real installation directory.

5. Make a new qt.conf inside installation directory/bin

That’s all. Now you can add this new installation into Qt Creator manually.

Old Android version, linux shared library and apk packer controlled by Android Studio

  1. Old Android version (4.4 on my side) didn’t look for shared library by SONAME inside. It only checks file name. For example, in recent Android version (7 or 8), one file named libcrypto.so whose SONAME is libcrypto.so.1.0.0 can be loaded by dependents successfully. But in old versions the system reported “dlopen failed to load libcrypto.so.1.0.0”.
  2. In Linux’s programming conventions, a shared library usually has name like libxxxx.so.x.y.z and a symbolic link named libxxxx.so would also be created pointing to the former. That’s OK in a normal Linux system, but has problems with Android’s app.  The android apk’s zip format didn’t recognize symbolic link, and as I described in 1. it also didn’t load shared library by  SONAME.
  3. Android Studio integrated CMake to build native libraries and it also packs what generated by CMake (app/build/intemediates/cmake/<debug-or-release>/obj/<arch>)/) to libs directory inside the apk. That’s good. But! But it packs only files with .so extension. So, files like libxxxx.so.x.y.z would be packed into the apk, and we don’t have any configurable option on both gradle file and CMakefile.txt to add them manually.

Android studio 3.0, modules and IDE symbol indexing

Long in short, after upgraded to Android Studio 3.0, symbols from aar binary modules cannot be resolved in IDE, although the building/make is successful. Clean or Rebuild project is useless.

 

Two steps solution:

  1. Change line
    compile('the-aar-module-name')

    to

    implementation project('the-aar-module-name')
  2. Select ‘Invalidate Caches / Restart‘ from File menu.

Strange behavior in WOW64 DLL loading in Windows 2008 R2

That is, if a 32bit DLL was loaded by CreateRemoteThread(), the DLL would be unloaded silently without DLL_PROCESS_DETACH invocation sent to DLLMain() of the DLL. There are indeed 2 weird issues, one is silent unloading, the other is no DLL_PROCESS_DETACH callback.

This occurs on WOW64 environment of Windows 2008 Server R2 only.  Windows 2012 and 2016 don’t have this issue, while x64 environment of 2008 also doesn’t have the issue.

To fix it, we can make the DLL depend on another DLL. The 2nd DLL can receive all notification callbacks of DLLMain(). This way can fix the callback issue. And by adding an extra LoadLibrary() call of 2nd DLL in 1st DLL’s DLL_PROCESS_ATTACH notification, we can keep the 2nd DLL in memory even if 1st DLL unloaded silently.

 

Selecting a correct order of API call sequences is important

In short, ffmpeg changes its API in recent versions. One of them is marking AVStream.codec as deprecated. On other side, a AVCodecParameters * AVStream.codecpar was added for codec information described in the stream. To decode data read from stream correctly, we must create a AVCodecContext through avcodec_alloc_context3(), copy codec information from AVStream.codecpar to this allocated AVCodecContext, and call avcodec_open2() to assign this AVCodecContext to AVCodec found by avcodec_finder_decoder() call.

Here is the point. We must call avcodec_parameters_to_context() to copy codec information to AVCodecContext before we call avcodec_open2() to assign AVCodecContext to AVCodec. If we incorrectly reversed this order, say, called avcodec_open2() before avcodec_parameters_to_context(), we can still decode many videos correctly, but we will encounter strange behavior when we try to play back .mkv or .mp4 files – Each call to decoding function will fail.

A simple shell script integrated to Xcode to generate and copy architecture adaptive dylib in

if [ "$CONFIGURATION" == "Debug" ]; then

   LIBFFMPEG_DIR="$PROJECT_DIR/../../ffmpeg/ios/universal/debug"

else

   LIBFFMPEG_DIR="$PROJECT_DIR/../../ffmpeg/ios/universal/release"

fi

for a in $ARCHS; do

    EXTRACT_ARCHS="$EXTRACT_ARCHS -extract $a"

done

lipo "$LIBFFMPEG_DIR/lib/libffmpeg.dylib" $EXTRACT_ARCHS -output "$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/libffmpeg.dylib"

if [ "$CODE_SIGNING_REQUIRED" == "YES" ]; then

   codesign -s "$EXPANDED_CODE_SIGN_IDENTITY" "$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/libffmpeg.dylib"

fi

install_name_tool -change "libffmpeg.dylib" "@executable_path/libffmpeg.dylib" "$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH"

Problem again. Assembly generated by clang or written manually, using integrated assembler or not

Simply, clang has an option '--no-integrated-as' so that the compiler invokes apple’s standalone 'as' assembler instead of using clang’s built-in. But, either has its own lost pieces.

  • Without '--no-integrated-as', clang would use its internal assembler. Unfortunately it doesn’t recognize the mnemonic 'ldmltfd'
  • With '--no-integrated-as', apple’s 'as’ assembler reports an error in pesudo instruction '.ios_version_min', which was apparently generated by clang itself.

Therefore I have no choice except for changing 'ldmltfd' to two simple instructions…

 

Some tricks in passing file descriptors through unix domain socket

Passing file descriptors through unix domain socket is well-known. But there still have some tricks in implementation. I spent one day to deal with it in Mac OS X by digging into xnu source.

  1. How to pass multiple file descriptors in one sendmsg() call?
    Simple. Put all file descriptors one by one after struct cmsghdr.
  2. Can I put multiple struct cmsghdrs with data? I noticed there are CMSG_FIRSTHDR() and CMSG_NXTHDR() defined in <sys/socket.h> 

    No. In xnu sources it checks msghdr.controllen with cmsghdr.cmsg_len. If they are not equal, a -EINVAL returned in sendmsg() call. That means only one cmsghdr can be put into msghdr.

The limitation is in OS X only. I haven’t check Linux and would do it soon or later.

Auto Layout UITableView cell resizing with multi-line UILabel issue in iOS7

There are many blogs and articles talked about this issue and resolution on Internet. But any of them has this or that problems in those solutions. So I took several hours on researches and got a perfect result, at least I think so. 🙂

Thought about device orientation change, table width and cell width will change. And since we are already use Auto Layout here, it is not a good practice to design cell with any implicit width, say, 320. in Interface Builder. Almost all solutions on Internet assumed 320 width implicitly so those solutions would fail on either landscape orientation, or, iPad if the app is a universal app and you use same cell design for both iPhone and iPad.

So, the problem is in [tableView: heightForRowAtIndexPath:] delegate method. This delegate method is required for iOS7 or the app would crash. To return a correct height value of the cell, we need those steps:

  1. Set cell width to table width after loaded the cell from xib.
  2. Set values for widgets including multi-line UILabel inside cell
  3. Call [cell setNeedsLayout] and [cell layoutIfNeeded]. After those 2 calls, system’s layout engine would set correct width for UILabels. Note at this time the label’s preferredMaxLayoutWidth is still zero or any value left from last using so the layout engine cannot wrap lines and adjust label’s frame correctly.
  4. Set label.preferredMacLayoutWidth = CGRectGetWidth(label.frame)
  5. Call [cell setNeedsLayout] and [cell layoutIfNeeded] again. This time labels have correct preferredMaxLayoutWidth and the layout engine would adjust label’s frame correctly
  6. Now you can call [systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] to get correct height.

Solutions on Internet usually don’t do step 1 and 5. In an invariant screen size they can get correct display but they are not a real solution for other cases.

However, from iOS8 there is a simple solution. Apple solved the issue. Just returning UITableViewAutomaticDimension or just not implementing the method will get correct result. But for apps having to maintain compatibility with iOS7, we still have to do something like this.