Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api tests vs unit tests #94

Open
headupinclouds opened this issue Jun 12, 2018 · 5 comments
Open

api tests vs unit tests #94

headupinclouds opened this issue Jun 12, 2018 · 5 comments

Comments

@headupinclouds
Copy link
Contributor

Review API tests (public/exported symbols) vs unit tests (private or hidden utility classes and functions). Most of the ACF tests fall under the API test category (they link against public symbols in the ACF_EXPORT classes + functions. We may also have utility hidden/private code that is tested only indirectly through the API calls, and that warrants more rigorous direct testing elsewhere. Two examples of private code that warrants direct testing are the local ACF shader classes and the optimized SIMD RGBA/texture unpacking code. We don't want to add such functionality to the API just to support devops testing tasks, so we have a few options.

  1. Ideally, we would build this code in OBJECT libraries so it could be reused in a test app and by the main ACF library, but OBJECT libraries aren't portable in general.
  • pros: optimal
  • cons: OBJECT libraries aren't portable
  1. As an alternative we can build that code as a support STATIC library, and the main ACF library can link to that code. The additional library should be more or less transparent to the user if they are using a SHARED ACF library (it is absorbed by the library) or if they are using a STATIC ACF library through CMake find_package(acf CONFIG REQUIRED) target_link_libraries(foo PUBLIC acf::acf) since the generated package configuration code will provide the transitive linking transparently.
  • pros: supports reuse (avoid recompilation)
  • cons: adds another library (mostly an issue for STATIC builds and non-cmake users -- in practice, it would be fairly messy to use ACF as a STATIC lib without CMake/Hunter anyway, due to the STATIC 3rdparty dependencies, so that seems to weaken the argument against introducing support STATIC libraries)
  1. If we want to avoid exporting an additional private library (it wouldn't have public headers but would be exported in the installation step), then we could collect the required source (sugar, etc) and just recompile the code directly into the test exe or via a test only static lib.
  • pros: avoid introducing an extra support lib in the ACF export set
  • cons: requires recompilation of the code (not a huge concern in ACF) and adds some additional build complexity

Since the ACF API tests will link to the compiled ACF library, and the ACF unit tests will link to some copy of private ACF code (already inside the the ACF library) the two tests should be managed in separate executables to avoid ODR conflicts.

headupinclouds added a commit that referenced this issue Jun 12, 2018
Related: #94

We need a separate executables for:
(1) the public (possibly shared) ACF api
(2) the private support class/functions used internally in ACF that require focused testing

* add SIMD channel conversion code to ACF (imgrated from drishti) and to private unit test
* move optimized separable triangle filter shader test to private unit test
* extract ogles_gpgpu::ACF::getImage() texture read code to acf/transfer.{h,cpp} as stand-alone functions for easier reuse (without require compilatino of GPUACF.{h,cpp}
* collect private unit test sources with sugar in ACF_TEST_SRCS variable and build into the acf unit test executable
headupinclouds added a commit that referenced this issue Jun 12, 2018
* add separate api and private/unit test executables

Related: #94

We need a separate executables for:
(1) the public (possibly shared) ACF api
(2) the private support class/functions used internally in ACF that require focused testing

* add SIMD channel conversion code to ACF (imgrated from drishti) and to private unit test
* move optimized separable triangle filter shader test to private unit test
* extract ogles_gpgpu::ACF::getImage() texture read code to acf/transfer.{h,cpp} as stand-alone functions for easier reuse (without require compilatino of GPUACF.{h,cpp}
* collect private unit test sources with sugar in ACF_TEST_SRCS variable and build into the acf unit test executable

* fix compilation

* fix typo

* add face image input arg test private test

* make pipeline test `—repeat=N` adaptive

```
if(travis_ci OR appveyor_ci)
  set(acf_repeat 5) # using emulator is slow!
else()
  set(acf_repeat 256) # provide a meaningful frame rate estimate
endif()
```
@headupinclouds
Copy link
Contributor Author

Separate public vs private tests added in #93 , will leave open for now in case of follow up efforts.

@ruslo
Copy link
Contributor

ruslo commented Jun 12, 2018

As an alternative we can build that code as a support STATIC library

Additional "cons": leads to pretty hairy CMake code, something like this if you want to support static/shared variants:

add_library(foo foo.cpp) # public API
add_library(boo STATIC boo.cpp) # private API

if(BUILD_SHARED_LIBS)
  # boo objects absorbed by foo, boo will not be installed
  set_target_properties(boo PROPERTIES POSITION_INDEPENDENT_CODE)
  target_link_libraries(foo PUBLIC $<BUILD_INTERFACE:boo>)
else()
  target_link_libraries(foo PUBLIC boo)
  install(TARGETS boo ...)
endif()

Also we will hit issue similar to this one if there will be usage requirements and some private headers installed:

we could collect the required source (sugar, etc) and just recompile the code directly into the test exe or via a test only static lib

Additional "cons": we may miss usage requirements

OBJECT libraries aren't portable

For the reference: https://cgold.readthedocs.io/en/latest/rejected/object-libraries.html

So as a summary:

(1) should be used in such cases, "target_link_libraries" and "Usage requirements" issues should be fixed in CMake itself, for the "No real sources" and "Name conflict" need to think about workarounds (CMake can add dummy source, CMake can use renamed copy of file).

(3) sounds like a simplest/cleanest workaround so far, affects only build performance, doesn't affect user's side.

@headupinclouds
Copy link
Contributor Author

  add_library(foo SHARED ${srcs})
  set_target_properties(boo PROPERTIES POSITION_INDEPENDENT_CODE)
  target_link_libraries(foo PUBLIC $<BUILD_INTERFACE:boo>)

☝️ Isn't the POSITION_INDEPENDENT_CODE redundant here? If you are building everything from source and are using a toolchain that can build aSHARED library, then I believe any STATIC library resulting from add_library(boo STATIC ...) will be compatible ("absorbable").

@headupinclouds
Copy link
Contributor Author

headupinclouds commented Jun 12, 2018

Also we will hit issue similar to this one if there will be usage requirements and some private headers installed: https://gitlab.kitware.com/cmake/cmake/issues/16324

From this comment (linked to in your initial issue) it seems CMake 3.12 will propagate usage requirements for OBJECT libraries. If I'm reading that correctly, that would leave Xcode OBJECT library incompatibilities outlined in your cgold post as the only remaining issue to be resolved for widespread portable use.

I see other people resorting to STATIC lib approximations of OBJECT libs in that post.

UPDATE: See https://gitlab.kitware.com/cmake/cmake/issues/18010. It seems CMake 3.12 will indeed "modernize" OBJECT libraries. 😄

@ruslo
Copy link
Contributor

ruslo commented Jun 13, 2018

Isn't the POSITION_INDEPENDENT_CODE redundant here? If you are building everything from source and are using a toolchain that can build a SHARED library

You mean toolchain like gcc-pic? Yes, but PIC applied automatically if you have add_library(foo foo.cpp) without specifier and you are using BUILD_SHARED_LIBS=ON.

E.g. if you want to build without toolchain (Linux + GCC) and have no POSITION_INDEPENDENT_CODE:

> git clone https://github.com/forexample/static-shared-pic-needed
> cd static-shared-pic-needed
> cmake -H. -B_builds -DBUILD_SHARED_LIBS=ON
> cmake --build _builds
Scanning dependencies of target boo
[ 25%] Building CXX object CMakeFiles/boo.dir/boo.cpp.o
[ 50%] Linking CXX static library libboo.a
[ 50%] Built target boo
Scanning dependencies of target foo
[ 75%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
[100%] Linking CXX shared library libfoo.so
/usr/bin/ld: libboo.a(boo.cpp.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
libboo.a: error adding symbols: Bad value

it seems CMake 3.12 will propagate usage requirements for OBJECT libraries

I saw that but haven't really tried since the other issues still remain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants