# Conditional code and precompilation

**URL:** https://discourse.julialang.org/t/conditional-code-and-precompilation/6301
**Category:** General Usage
**Tags:** question, package, compilation
**Created:** [October 6, 2017, 10:46pm UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301 "2017-10-06T22:46:59Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 6, 2017, 10:46pm UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/1 "2017-10-06T22:46:59Z")

</div>

I am developing a package that is designed to be used either by standard Julia or by Julia library embedded in a third party application. Most of the code is the same in either mode, but a few functions are currently defined conditionally like this

```julia
const embedded = isembedded() # true when embedded, false otherwise
if embedded
    f() = "one implementation"
else
    f() = "another implementation"
end

```

Unfortunately, this approach does not work if I want to have my package precompiled. Since pre-compilation is always done by a standard julia instance, the precompiled code will always have `embedded` set to `false`.

I could probably redefine `Base.julia_cmd()` and `Base.LOAD_CACHE_PATH[1]` in the embedded case, but this will result in a duplicate cache for all packages, not only mine.

What is the recommended approach in a situation like this? I thought this problem would be resolved in pyjulia, but it looks like [it is not](https://github.com/JuliaPy/pyjulia/issues/128).

One solution that comes to mind is to move the variable code to the ` __init__ ` method:

```julia
function __init__ ()
    if isembedded()
        global f() = "one implementation"
    else
        global f() = "another implementation"
    end
end
```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [October 6, 2017, 11:56pm UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/2 "2017-10-06T23:56:39Z")

</div>

Why not

```julia
function f()
    if isembedded()
         "one way"
    else
        "other way"
    end
end

```

Is the runtime cost of `isembedded()` really so bad?

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [October 7, 2017, 12:01am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/3 "2017-10-07T00:01:55Z")

</div>

Use `@static if`.

---

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 7, 2017, 12:20am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/4 "2017-10-07T00:20:36Z")

</div>

Can you elaborate on this? I don’t see how the `@static` macro will help. It will be expanded during precompilation and embedded system will still see the non-embedded code.

---

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 7, 2017, 12:41am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/5 "2017-10-07T00:41:30Z")

</div>

The problem is actually harder than I thought. The main source of differences between embedded and non-embedded codes is in the way I call the third-party API. In the embedded mode, the API function `f` can be called simply as

```julia
ccall(:f, ...)

```

because the symbol `f` is in the main binary. In the embedded mode, the API calls must include the path to the dynamic library:

```julia
const lib = "path/to/lib.so"
ccall((:f, lib), ...)

```

I currently deal with this by conditionally defining a macro that given `:f` would expand into either `:f` or `(:f, lib)`. I borrowed this approach from [PyCall](https://github.com/JuliaPy/PyCall.jl/blob/314ac274326e78f12fbcb73ae0f17f63a3f4bba9/src/startup.jl#L124).

Since `ccall` requires a compile-time constant I would have to replace every instance of

```julia
f() = ccall((@sym :f), ...)

```

with

```julia
function f()
   if isembedded()
       ccall(:f, ...)
   else
       ccall((:f, lib), ...)
   end
end

```

but I am afraid this will still attempt to `dlopen` the library while running in the embedded mode. This will not work because the application is statically linked and the API implementation in the app is not compatible with that in the library. I am not sure how pyjulia copes with this. Most likely in will not work properly in a statically linked python.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [October 7, 2017, 12:44am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/6 "2017-10-07T00:44:53Z")

</div>

> [@Alexander\_Belopolsky](#):
>
> Can you elaborate on this? I don’t see how the @static macro will help. It will be expanded during precompilation and embedded system will still see the non-embedded code.

Don’t you want to make it compile to have one function when embedded and one function when not?

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [October 7, 2017, 12:53am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/7 "2017-10-07T00:53:16Z")

</div>

`@static` will be exactly the same as what you were doing so it won’t solve any problem here.

If `isembedded()` is expensive you can just cache it in ` __init__ ` to a global and branch on that.

> but I am afraid this will still attempt to dlopen the library while running in the embedded mode.

That should not be a problem. The `dlopen` will fail but as long as your code doesn’t execute that branch no error would be raised.

---

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 7, 2017, 12:56am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/8 "2017-10-07T00:56:48Z")

</div>

Let me make the problem more specific. My function `f` is a Julia wrapper to the namesake 3rd party C function. The 3rd party API comes in two flavors: it is available to plugins running inside an application or can be loaded from a DLL. In the first case, my function is simply

```julia
f() = ccall(:f, ...)

```

while in the second, the path to the library should be specified

```julia
f() = ccall((:f, lib), ...)

```

---

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 7, 2017, 1:06am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/9 "2017-10-07T01:06:52Z")

</div>

> [@yuyichao](#):
>
> The dlopen will fail but as long as your code doesn’t execute that branch no error would be raised.

Thanks, @yuyichao - I’ll try that. What do you think about the following alternative:

```julia
const N = .. # Number of the API functions
const API = zeros(Ptr{Void}, N)
f() = ccall(API[1], ...)
... # all the other API functions

function __init__ ()
   if !isembedded()
      Libc.dlopen(...)
   end
   API[1] = cglobal(:f)
   ... # all the other API functions
end

```

This will still incur the indirection overhead for each API call, but the code size will be 2x smaller.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [October 7, 2017, 1:13am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/10 "2017-10-07T01:13:17Z")

</div>

You should use `dlsym` instead of `cglobal` and you can use individual slots instead of an Array.  
And you should be able to write a macro do that at the call side. I thought that’s what PyCall used at some point.

---

<div class="post-metadata">

### Author: ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)
#### Post date: [October 7, 2017, 1:18am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/11 "2017-10-07T01:18:41Z")

</div>

> [@yuyichao](#):
>
> I thought that’s what PyCall used at some point.

PyCall does the [following](https://github.com/JuliaPy/PyCall.jl/blob/314ac274326e78f12fbcb73ae0f17f63a3f4bba9/src/startup.jl#L124):

```julia
if libpython == nothing
    macro pysym(func)
        esc(func)
    end
else
    macro pysym(func)
        :(($(esc(func)), libpython))
    end
end

```

and uses `@pysym :f` at the call sites. This approach [does not work](https://github.com/JuliaPy/pyjulia/issues/128).

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [October 7, 2017, 1:24am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/12 "2017-10-07T01:24:27Z")

</div>

Yes, I know what PyCall is doing **now** and I know it doesn’t work.  
I said I thought it did something else before.

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [October 7, 2017, 1:33am UTC](https://discourse.julialang.org/t/conditional-code-and-precompilation/6301/13 "2017-10-07T01:33:57Z")

</div>

e.g. [https://github.com/JuliaPy/PyCall.jl/commit/600a7f5b6d3abb6c54e8849817bb003de6b5c965](https://github.com/JuliaPy/PyCall.jl/commit/600a7f5b6d3abb6c54e8849817bb003de6b5c965)
