# How do I make a driver?

**URL:** <https://discourse.julialang.org/t/how-do-i-make-a-driver/136095>\
**Category:** General Usage\
**Created:** [March 8, 2026, 5:32pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095 "2026-03-08T17:32:05Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 8, 2026, 5:32pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/1 "2026-03-08T17:32:05Z")

</div>

I have a main program. It will load any one of various drivers (plugins?), depending on a configuration file. Each driver will operate a hardware device or accept files from the outside. The drivers have to be all listed in `Project.toml`, but only one can be loaded, because they all define and export the same function names. How do I do this?

I tried `@less using`, to see the source code of `using`, but the REPL hung and I had to type `^C`. I tried `@less using()`, but got an error because `using` is not a function. Is there a function I can call to load a module, whose name is not known until runtime, in the same way as `using`?

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [March 8, 2026, 7:23pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/2 "2026-03-08T19:23:12Z")

</div>

I suspect there might be better solutions, but you could use `eval` for this:

If this is `main.jl`

```julia
module A1
    export foo
    foo(x) = x
end

module A2
    export foo
    foo(x) = 2x
end

moduleName = Symbol(ARGS[1])
@eval using .$(moduleName)
println(foo(1))

```

You would get

```bash
$ julia main_test.jl A1
1

$ julia main_test.jl A2
2

```

Using `@eval` comes with the usual caveats of execution any code you pass to it from the outside of course (whatever you read from the config file).  
Depending on if you need the list of drivers/plugins to be expandable from the outside, you could just check if the runtime value of the plugin name is in a list of allowed names or something like that.

But if I understand this correctly, the `@eval using $()` expression would at least error if you try to interpolate anything that’s not just a symbol into it. So it should be reasonably restrictive already.

Note the dot `.` in my example since I’m using modules defined directly in `Main`. In your case it would probably be `@eval using $(...)` without the leading `.`.

PS: If your list of possible plugins is fixed in advance, you can also just write an `if` statement

```julia
if moduleName == :A1
    using .A1
elseif ...
    ...
end

```

which would avoid `@eval` altogether. Of course it’s not as concise, but might be enough in your situation and is quite straightforward to understand. For some reason I thought that this doesn’t work, but I can’t recall why… after all, conditional loading of packages is also what is done by some people in the `startup.jl` file, e.g. something like

```julia
if isinteractive()
     using Revise
end

```

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [March 8, 2026, 8:05pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/3 "2026-03-08T20:05:46Z")

</div>

I think you should always load all the drivers and solve this with dispatch. Here is how this could look

- Have on abstract type for the plugins e.g.

```julia-auto
# module structure optional but good style and helps show the dependencies in this example
module DriversBase

# export interface functions
export load, end

abstract type AbstractDriver end

# also define the functions the drivers implement
# so the driver can add their dispatches
# also it's nice to see the whole interface together in one file
"""
    load(::AbstractDriver)
Set up the driver
"""
function load end

"""
    dostuff(::AbstractDriver, msg::String)
Do stuff with the message.
"""
function dostuff end

end #module

```

- Have each driver/plugin define a type and then add their methods to the aforementioned functions:

```julia-auto
module FooDriver

# import DriversBase module from parent
using ..DriversBase

# export this driver's type
export FooDriver
# note we don't need to reexport the functions because they are already exported by Drivers module

# type for dispatch
struct FooDriver <: DriversBase.AbstractDriver end

## implement the functions
function DriversBase.load(::FooDriver)
    # ...
end

function DriversBase.dostuff(::FooDriver, msg)
    # ...
end

end #module

```

- Pull this together into a package/module

```julia-auto
module MyDriverCollection

export load, dostuff
export FooDriver #, BarDriver, ...

include("drivers_base.jl")
using DriversBase

include("foo.jl")
using FooDriver

# and so on
end # module

```

Then all you need to do to switch drivers is write function that return one of these type:

```julia-auto
function decide_driver(path)
    # parse file and return appropriate type
    return FooDriver()
end

```

Note: this decision is inherently type unstable so be sure to use a function barrier to contain it properly, i.e. do something like this:

```julia-auto
function main()
    # ...
    driver = decide_driver()
    do_everything_else(driver) # 1 runtime dispatch but then type stable again
end

```

Also disclaimer: I wrote this up on my phone, so minor mistakes are possible. But overall this approach should work. Feel free to ask if it doesn’t work out-of-the-box and you have trouble getting it right 🙂

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 9, 2026, 2:45am UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/4 "2026-03-09T02:45:53Z")

</div>

> [@Sevi](#):
>
> but you could use `eval` for this

Could I run into world age bugs?

> [@Sevi](#):
>
> Using `@eval` comes with the usual caveats of execution any code you pass to it from the outside of course (whatever you read from the config file).

Doesn’t the module name have to be listed in `Project.toml` for `using` to succeed?

> [@Sevi](#):
>
> If your list of possible plugins is fixed in advance

It isn’t, but for a particular installation, the driver is generally fixed, though the software may need to be upgraded.

> [@abraemer](#):
>
> abstract type for the plugins

Type of what? All the drivers export `startDriver()`, `justStopDriver()`, and `waitDriverFinish()`, and there’s nothing obvious for it to be a type of.

> [@abraemer](#):
>
> Then all you need to do to switch drivers

There’s no need or way to switch drivers once the program’s running.

> [@abraemer](#):
>
> Feel free to ask if it doesn’t work out-of-the-box and you have trouble getting it right 🙂

It’ll be at least a few weeks. I have one half-written driver and am going to start another tonight, and it’ll be next month at the earliest before I can buy hardware to write a hardware driver.

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [March 9, 2026, 9:12am UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/5 "2026-03-09T09:12:17Z")

</div>

> [@phma](#):
>
> Could I run into world age bugs?

In general, yes. But without knowing more about your code, it’s hard to make accurate predictions. My guess is everything will be fine as long as you hit the “top-level” of your main module after dynamically loading the plugins and before your other functions execute. But I’m not even sure if `using ...` will create the same type of problems you would have when you try to call a function defined in `@eval` directly (before returning to the top-level).

> [@phma](#):
>
> Doesn’t the module name have to be listed in `Project.toml` for `using` to succeed?

Sure (or the module is defined in your code somewhere). That’s why I think that `@eval using ...` will error for anything that doesn’t parse to a valid “using” expression and it’s quite safe to use in this situation.

* * *

All that being said, I think @abraemer’s approach probably makes more sense here. It requires a bit of extra code, but has the additional benefit that other people (including you) can define new drivers/plugins later independently of your main package. Even if you don’t need to switch the driver dynamically, it might be convenient for testing or for writing new drivers to have a function that can turn a driver on/off.

> [@phma](#):
>
> Type of what? All the drivers export `startDriver()`, `justStopDriver()`, and `waitDriverFinish()`, and there’s nothing obvious for it to be a type of.

You just create a new type representing the driver itself. This will allow these three functions to dispatch on the driver type (by which Julia will automatically choose the desired driver for you without the need of a “dynamic `using` expression”.

E.g. the driver called `Diver1` implements the methods of this function specific to that driver

```julia
startDriver(driver::Driver1) = ...
justStopDriver(driver::Driver1) = ...
waitDriverFinish(driver::Driver1) = ...

```

And similarly for all other drivers. The argument `driver` will likely not be used inside the method definition, but that’s fine.

You still have to carry around the driver explicitly for this to work and be performant. But you could also make a global variable that holds the “current driver” and define a fallback method like

```julia
startDriver() = startDriver(current_driver())
justStopDriver() = justStopDriver(current_driver())
waitDriverFinish() = waitDriverFinish(current_driver())

```

But this might impact performance, depending on how/where these functions are used.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [March 9, 2026, 5:39pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/6 "2026-03-09T17:39:40Z")

</div>

> [@phma](#):
>
> but only one can be loaded, because they all define and export the same function names

> [@phma](#):
>
> There’s no need or way to switch drivers once the program’s running.

It is certainly possible to achieve this design, but why would you do it like that?

I feel such artificial limitations are ugly. One practical drawback is that it will make testing your packages a pain.

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 9, 2026, 7:05pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/7 "2026-03-09T19:05:03Z")

</div>

This is not an artificial limitation, but I can’t tell you why, because the project is so far a trade secret. There is one planned driver which will drive two hardware devices.

I’ve done some plotting. I use `CairoMakie` or `GLMakie`, but not both at the same time, because they export functions with the same name. To change it, I have to edit the source code and restart the program. I’d like to do something similar, but choosing the module at the start of runtime by reading a config file.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [March 9, 2026, 8:16pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/8 "2026-03-09T20:16:02Z")

</div>

> [@phma](#):
>
> because they export functions with the same name. To change it, I have to edit the source code and restart the program.

Or just rename:

```julia
using SomePackage: original_name as new_name

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [March 9, 2026, 8:17pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/9 "2026-03-09T20:17:46Z")

</div>

> [@phma](#):
>
> I’d like to do something similar, but choosing the module at the start of runtime by reading a config file.

I think that may make precompilation impossible. Or at least less straightforward.

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 9, 2026, 8:22pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/10 "2026-03-09T20:22:50Z")

</div>

What for? There’s no need to have two of these drivers running at once.

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [March 9, 2026, 8:27pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/11 "2026-03-09T20:27:22Z")

</div>

If I follow, you have one program where you want to be able to select which driver to use. However once the program is running the driver is fixed.

I am not an expert in this area, but presumably you could organize your code like Makie, CairoMakie, and GLMakie?

Or perhaps you could use extensions to determine which driver is loaded?

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 9, 2026, 8:32pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/12 "2026-03-09T20:32:00Z")

</div>

What do you mean by extensions?

---

<div class="post-metadata">

**Author:** ![JonasWickman](https://avatars.discourse-cdn.com/v4/letter/j/9de0a6/32.png) [@JonasWickman](https://discourse.julialang.org/u/JonasWickman)\
**Post date:** [March 9, 2026, 8:55pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/13 "2026-03-09T20:55:27Z")

</div>

This is rather paranthetical to your actual problem, but you can load both `CairoMakie` and `GLMakie`, and switch between which backend is active by doing:

```julia-auto
using CairoMakie
using GLMakie
CairoMakie.activate!() # Sets CairoMakie as the active backend for plotting

# Do some plotting with CairoMakie

GLMakie.activate!() # Set GLMakie as the active backend 

# Do some plotting with GLMakie

```

I have no idea how this is implemented, but at least this should make plotting a bit less of a pain.

---

<div class="post-metadata">

**Author:** ![dilumaluthge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilumaluthge/32/29283_2.png) [@dilumaluthge](https://discourse.julialang.org/u/dilumaluthge)\
**Post date:** [March 9, 2026, 9:39pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/14 "2026-03-09T21:39:25Z")

</div>

I agree that this would be my first recommendation:

> [@abraemer](#):
>
> I think you should always load all the drivers and solve this with dispatch. Here is how this could look

But alternatively, this seems like a good use case for [Preferences](https://github.com/JuliaPackaging/Preferences.jl). Maybe something like:

```julia
module MyPackage

using Preferences: Preferences, @load_preference

const driver = @load_preference("driver")

# We're at top-level, so no need for @static
if driver == "foo"
    include("foo_driver_functions.jl")
elseif driver == "bar"
    include("bar_driver_functions.jl")
elseif driver == "baz"
    include("baz_driver_functions.jl")
else
    error("Unsupported driver name: $driver")
end

end # module MyPackage

```

Or alternatively, if the drivers are all separate packages:

```julia
module MyPackage

using Preferences: Preferences, @load_preference

const driver = @load_preference("driver")

# We're at top-level, so no need for @static
if driver == "foo"
    using FooDriver
elseif driver == "bar"
    using BarDriver
elseif driver == "baz"
    using BazDriver
else
    error("Unsupported driver name: $driver")
end

end # module MyPackage

```

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [March 9, 2026, 10:29pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/15 "2026-03-09T22:29:11Z")

</div>

> [@phma](#):
>
> What do you mean by extensions?

> **[Conditional loading of code in packages (Extensions) - 5. Creating Packages ·...](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions))**
>
> The PkgTemplates package offers an easy, repeatable, and customizable way to generate the files for a new package. It can also generate files needed for Documentation, CI, etc. We recommend that you use PkgTemplates for creating new packages instead...

I guess that was what was meant by extensions. They have a similar purpose, but it’s more about dynamically activating some functionality in PackageA that is required for working nicely with PackageB (but only when PackageB is actually loaded with `using PackageB`). So in your scenario it would again require a `using MyDriver` statement to activate the corresponding extension, which you want to avoid, if I understand correctly.

---

<div class="post-metadata">

**Author:** ![phma](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/phma/32/6576_2.png) [@phma](https://discourse.julialang.org/u/phma)\
**Post date:** [March 9, 2026, 10:54pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/16 "2026-03-09T22:54:35Z")

</div>

`Preferences` sounds workable, but IIRR its file is in the source tree. I’m already using `ConfParser` so that the config file can be in `/etc` (it’s in `~/.config` for now). Can I do the same with `ConfParser`?

---

<div class="post-metadata">

**Author:** ![dilumaluthge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dilumaluthge/32/29283_2.png) [@dilumaluthge](https://discourse.julialang.org/u/dilumaluthge)\
**Post date:** [March 9, 2026, 10:59pm UTC](https://discourse.julialang.org/t/how-do-i-make-a-driver/136095/17 "2026-03-09T22:59:33Z")

</div>

I believe that there is a way to have a depot-wide preference, but off the top of my head I don’t know how to set that up.

Preferences is special because it hooks into precompilation. I don’t think other packages currently offer this functionality\[1\].

* * *

1. Presumably they could, although they’d need to call private Base Julia internals.
